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> ...
随机推荐
- 关于nodejs下载组件经常失败的问题
由于最近在刚开始做一个前台element和mybatisplus的项目,但是在使用nodejs下载vue的脚手架和各种组件时,会经常出现下载失败的问题,进而导致前台无法启动. 在网上查询之后发现在下载 ...
- canvas之背景特效
需具备js基础知识以及canvas相关方法(可查阅相关文档) 下面是一篇有关js与canvas的背景特效 基于面向过程的思维 <!DOCTYPE html> <html> &l ...
- restframework中的那些参数你知道吗?
序列化是很重要的过程, 在构建数据结构的时候, 往往会出现很多意想不到的问题, 有一些参数你要用, 但是没有办法穿过来, 怎么办> 今天这篇博客就是写我之前的一个小项目中用restframewo ...
- 编写radware的负载配置
radware如何添加负载服务? 笔者在新添加radware的新负载服务的时候,是习惯去看下上一个负载服务的ID 和 节点服务的ID 号 分别是多少,主要是避免ID冲突,把其他服务顶替下去,同时以后这 ...
- PHP批量清理MIP-cache缓存(内附在线mipcache清理工具)
MIP是什么?我就不多说了把. MIPCache 又是什么? 科普一下:MIPCache 是一套基于代理的 CDN 缓存系统.可用于缓存所有被某度相关页面引用或者从百度相关服务点出的 MIP 页面.当 ...
- angular2路由之routerLinkActive指令
angular2的routerLinkActive指令在路由激活时添加样式class .red{ color: red;} <a routerLink="/user/login ...
- day 16 初试面试对象
1.初识面向对象 面向过程: 一切以事物的发展流程为中心 面向对象: 一切以对象为中心.一切皆为对象.具体的某一个事务就是对象 打比 ...
- 『Linux基础 - 2 』操作系统,Linux背景知识和Ubuntu操作系统安装
这篇笔记记录了以下几个知识点: 1.目前常见的操作系统及分类,虚拟机 2.Linux操作系统背景知识,Windows和Linux两个操作系统的对比 3.在虚拟机中安装Ubuntu系统的详细步骤 OS( ...
- 北京Uber优步司机奖励政策(4月4日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- CF 1051 F. The Shortest Statement
F. The Shortest Statement http://codeforces.com/contest/1051/problem/F 题意: n个点,m条边的无向图,每次询问两点之间的最短路. ...