ZOJ 3229 Shoot the Bullet(有源汇的上下界最大流)
Description
Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utopia where humans and other beings such as fairies, youkai(phantoms), and gods live peacefully together. Shameimaru Aya is a crow tengu with the ability to manipulate wind who has been in Gensokyo for over 1000 years. She runs the Bunbunmaru News - a newspaper chock-full of rumors, and owns the Bunkachou - her record of interesting observations for Bunbunmaru News articles and pictures of beautiful danmaku(barrange) or cute girls living in Gensokyo. She is the biggest connoisseur of rumors about the girls of Gensokyo among the tengu. Her intelligence gathering abilities are the best in Gensokyo!

During the coming n days, Aya is planning to take many photos of m cute girls living in Gensokyo to write Bunbunmaru News daily and record at least Gx photos of girl x in total in the Bunkachou. At the k-th day, there are Ck targets, Tk1, Tk2, ..., TkCk. The number of photos of target Tki that Aya takes should be in range [Lki, Rki], if less, Aya cannot write an interesting article, if more, the girl will become angry and use her last spell card to attack Aya. What's more, Aya cannot take more than Dk photos at the k-th day. Under these constraints, the more photos, the better.
Aya is not good at solving this complex problem. So she comes to you, an earthling, for help.
Input
There are about 40 cases. Process to the end of file.
Each case begins with two integers 1 <= n <= 365, 1 <= m <= 1000. Then m integers, G1, G2, ..., Gm in range [0, 10000]. Then n days. Each day begins with two integer 1 <= C <= 100, 0 <= D<= 30000. Then C different targets. Each target is described by three integers, 0 <= T < m, 0 <= L <= R <= 100.
Output
For each case, first output the number of photos Aya can take, -1 if it's impossible to satisfy her needing. If there is a best strategy, output the number of photos of each girl Aya should take at each day on separate lines. The output must be in the same order as the input. If there are more than one best strategy, any one will be OK.
Output a blank line after each case.
题目大意:文文要要给幻想乡中的少女拍照。一共有n天,m个少女,在这n天中文文至少要给少女i(i<m)拍Gi张照片。在第t(t<n)中,只能拍Dt张照片,只能给特定的Ct个人拍照,而且每个人至少拍L张,但是少女只给文文拍R张。问文文能否完成任务,在完成任务的情况下最多能拍多少张照片。
思路:预备知识,无源无汇的上下界可行流,见SGU 194 Reactor Cooling(无源无汇上下界可行流)
然后来建图:引入源点S汇点T,n天一天一点,m个少女每人一点。S到每一天连一条边,上界为Dt,下界为0。每个少女到汇点连一条边,上界为无穷大,下界为Gi。对每一天,连一条边到所有要拍照的少女,下界为L,上界为R。然后引入超级源点SS,超级汇点TT,像无源无汇上下界可行流那样建边,然后T到S连一条边,容量为无穷大。最后从源点S到汇点T跑一遍最大流就是答案,每条边容量的取法和无源无汇上下界可行流一样。
小证明:原图为什么是那样建的我就不解释了。
至于加入超级源点和超级汇点之后为什么要连一条边T→S呢,因为根据无源无汇上下界可行流的做法,原图无源无汇,是应该有一个环的,而现在没有……
之后再从S到T跑一遍,会不会影响之前的流量下界呢?满足下界是来自于点与超级源点和超级汇点之间的边,如果我们把这两个点删掉,边的容量就没法变了,也就不会影响到流量下界。而我没有删掉,是因为若求出可行解之后,超级源点和超级汇点关联的边都应该是满流量的,再跑最大流不可能经过这两个点。
那么跑可行流的时候,和跑最大流的时候,流量是分开算的,那为什么不用加上原来可行流的流量呢?因为原先我们连了一条边T→S,根据无源无汇图中,每个点的入流等于出流,跑可行流的流量已经存在了T→S这条边中,跑最大流就时候,T→S的反向边就有了可行流的容量。所以跑最大流的时候会加上可行流的容量,就不用再加一遍了。
PS:之前以为输出每天的拍照数,后面跑样例的时候发现输出不对……然后把输出改成每天每人,忘了改数组大小RE了一遍>_<
代码(190MS):
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int MAXN = ;
const int MAXE = ;
const int INF = 0x3fff3fff; struct SAP {
int head[MAXN], gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int to[MAXE], next[MAXE], flow[MAXE], cap[MAXE];
int n, ecnt, st, ed; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, int c) {
to[ecnt] = v; cap[ecnt] = c; flow[ecnt] = ; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; cap[ecnt] = ; flow[ecnt] = ; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d->%d %d\n", u, v, c);
} void bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<int> que; que.push(ed);
dis[ed] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
++gap[dis[u]];
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(cap[p ^ ] > flow[p ^ ] && dis[v] > n) {
dis[v] = dis[u] + ;
que.push(v);
}
}
}
} int Max_flow(int ss, int tt, int nn) {
st = ss, ed = tt, n = nn;
int ans = , minFlow = INF, u;
for(int i = ; i <= n; ++i) {
cur[i] = head[i];
gap[i] = ;
}
u = pre[st] = st;
bfs();
while(dis[st] < n) {
bool flag = false;
for(int &p = cur[u]; p; p = next[p]) {
int &v = to[p];
if(cap[p] > flow[p] && dis[u] == dis[v] + ) {
flag = true;
minFlow = min(minFlow, cap[p] - flow[p]);
pre[v] = u;
u = v;
if(u == ed) {
ans += minFlow;
while(u != st) {
u = pre[u];
flow[cur[u]] += minFlow;
flow[cur[u] ^ ] -= minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - ;
for(int p = head[u]; p; p = next[p]) { int &v = to[p];
if(cap[p] > flow[p] && dis[v] < minDis) {
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == ) break;
++gap[dis[u] = minDis + ];
u = pre[u];
}
return ans;
}
} G; int n, m, c, d, l, r, x;
int f[MAXN], down[MAXE], id[MAXE]; int main() {
while(scanf("%d%d", &n, &m) != EOF) {
G.init();
memset(f, , sizeof(f));
int s = n + m + , t = s + ;
int ss = t + , tt = ss + ;
for(int i = ; i <= m; ++i) {
scanf("%d", &x);
f[i] -= x;
f[t] += x;
G.add_edge(i, t, INF);
}
int cnt = ;
for(int i = ; i <= n; ++i) {
scanf("%d%d", &c, &d);
G.add_edge(s, i + m, d);
while(c--) {
scanf("%d%d%d", &x, &l, &r);
f[i + m] -= l;
f[x + ] += l;
down[++cnt] = l; id[cnt] = G.ecnt;
G.add_edge(i + m, x + , r - l);
}
}
int sum = ;
for(int i = ; i <= t; ++i) {
if(f[i] > ) sum += f[i], G.add_edge(ss, i, f[i]);
else G.add_edge(i, tt, -f[i]);
}
G.add_edge(t, s, INF);
if(sum != G.Max_flow(ss, tt, tt)) puts("-1");
else {
printf("%d\n", G.Max_flow(s, t, tt));
for(int i = ; i <= cnt; ++i) printf("%d\n", down[i] + G.flow[id[i]]);
}
puts("");
}
}
ZOJ 3229 Shoot the Bullet(有源汇的上下界最大流)的更多相关文章
- Shoot the Bullet(有源汇带上下界最大流)
有源汇带上下界最大流 在原图基础上连一条汇点到源点流量为inf的边,将有源汇网络流转化为无源汇网络流用相同方法判断是否满流,如果满流再跑一边源点到汇点的最大流就是答案 例题:Shoot the Bul ...
- ZOJ3229 Shoot the Bullet(有源汇的上下界最大流)
#pragma warning(disable:4996) #include <iostream> #include <cstring> #include <string ...
- ZOJ 3229 Shoot the Bullet(有源汇上下界最大流)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 题目大意: 一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给 ...
- zoj3229 Shoot the Bullet(有源汇有上下界的最大流)
题意: 一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给给定的C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌 ...
- ZOJ 3229 Shoot the Bullet | 有源汇可行流
题目: 射命丸文要给幻想乡的居民照相,共照n天m个人,每天射命丸文照相数不多于d个,且一个人n天一共被拍的照片不能少于g个,且每天可照的人有限制,且这些人今天照的相片必须在[l,r]以内,求是否有可行 ...
- [poj] 2396 [zoj] 1994 budget || 有源汇的上下界可行流
poj原题 zoj原题 //注意zoj最后一行不要多输出空行 现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出.列代表不同赛区支出的矩阵.组委会曾经开会讨论过各类支出的总和,以及各赛区 ...
- LOJ116 - 有源汇有上下界最大流
原题链接 Description 模板题啦~ Code //有源汇有上下界最大流 #include <cstdio> #include <cstring> #include & ...
- 【Loj116】有源汇有上下界最大流(网络流)
[Loj116]有源汇有上下界最大流(网络流) 题面 Loj 题解 模板题. #include<iostream> #include<cstdio> #include<c ...
- loj #116. 有源汇有上下界最大流
题目链接 有源汇有上下界最大流,->上下界网络流 注意细节,重置cur和dis数组时,有n+2个点 #include<cstdio> #include<algorithm> ...
- loj #117. 有源汇有上下界最小流
题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. #include<cstdio> #include<algorithm> ...
随机推荐
- DW CS5序列号
先要改host文件,以防止其连接 Adobe 的激活验证服务器 1. 用记事本编辑“C:\Windows\System32\Drivers\etc\”目录下的 hosts 文件, 在末尾加上: 127 ...
- shell脚本显示当前主机系统信息
编写脚本/root/bin/systeminfo.sh, 当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小. vim /root/bin/system ...
- linux系统基础之-----磁盘结构(基于centos7.4 1708)
- 【若泽大数据实战第二天】Linux命令基础
Linux基本命令: 查看IP: ifconfig 或者 hostname -i(需要配置文件之后才可以使用) ipconfig(Windows) 关闭防火墙: Service iptables st ...
- jQuery树形控件zTree使用小结
作者:Fonour 字体:[增加 减小] 类型:转载 时间:2016-08-02我要评论 这篇文章主要为大家详细介绍了jQuery树形控件zTree使用方法,zTree树插件的基本使用方法,感兴趣的小 ...
- restframework中的那些参数你知道吗?
序列化是很重要的过程, 在构建数据结构的时候, 往往会出现很多意想不到的问题, 有一些参数你要用, 但是没有办法穿过来, 怎么办> 今天这篇博客就是写我之前的一个小项目中用restframewo ...
- Vue directive自定义指令+canvas实现H5图片压缩上传-Base64格式
前言 最近优化项目-手机拍照图片太大,回显速度比较慢,使用了vue的自定义指令实现H5压缩上传base64格式的图片 canvas自定义指令 Vue.directive("canvas&qu ...
- socketpair通信
1.线程间通信(参考安卓源码InputTransport.cpp) #include <pthread.h> #include <sys/types.h> /* See NOT ...
- Django的安装创建与连接数据库
HTTP协议简介 HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP).通过使用网 页浏览器.网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端 口为 ...
- gem install ruby-odbc失败
解决: brew install unixodbc gem install ruby-odbc -v '0.99998'