标签:algorithm 算法 网络流 有上下界网络流 dfs
题目:ZOJ Problem Set - 3229 Shoot the Bullet
分类:有源有汇有上下界网络流
题意:有 n 天和 m 个girls,然后每天给一部分girls拍照,每个girls 有拍照的下限,即最少要拍这么多张,然后每天有k个女孩拍照,摄影师最多可以拍num张,然后 k 个女该每天拍照数量值有上下限,然后问你有没有满足这样条件的给女孩拍照的最大方案,然后按照输入输出每天给女孩拍照的张数。
做这道题目推荐先做:这儿
分析:首先它让你判断能不能满足条件。
按照题目给出的条件很容易建图:
s ---> 天数,
天数 ----> girls
girls ----> t
(流量都为当前的上界减去下界)
这样的话就建图成功了,但是这样不能判断,我们在加一条边 t -----> s,流量无穷
这样的话原图编程一个循环图,即前面推荐的题目,按照那样的方法建图,然后求一次最大流看看是否满流。
然后加入满流的话,就可以考虑第二个问题了。每天给女孩拍照的最大的张数?
这样我们可以删去 t ----> s 得边,然后求一次 s 到 t 的最大流。
然后按照题目要求输出流量就ok。
PS:伤在了英语上,没有读懂题目,然后错了无数次,最后终于懂了,坑题目。
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <queue> #define Del(a,b) memset(a,b,sizeof(a)) using namespace std; const int inf = 0x3f3f3f3f; const int N = 1550; struct Node { int from,to,cap,flow; }; vector<int> v[N]; vector<Node> e; int vis[N]; //构建层次图 int cur[N]; void add_Node(int from,int to,int cap) { e.push_back((Node){from,to,cap,0}); e.push_back((Node){to,from,0,0}); int tmp=e.size(); v[from].push_back(tmp-2); v[to].push_back(tmp-1); } bool bfs(int s,int t) { Del(vis,-1); queue<int> q; q.push(s); vis[s] = 0; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=0;i<v[x].size();i++) { Node tmp = e[v[x][i]]; if(vis[tmp.to]<0 && tmp.cap>tmp.flow) //第二个条件保证 { vis[tmp.to]=vis[x]+1; q.push(tmp.to); } } } if(vis[t]>0) return true; return false; } int dfs(int o,int f,int t) { if(o==t || f==0) //优化 return f; int a = 0,ans=0; for(int &i=cur[o];i<v[o].size();i++) //注意前面 ’&‘,很重要的优化 { Node &tmp = e[v[o][i]]; if(vis[tmp.to]==(vis[o]+1) && (a = dfs(tmp.to,min(f,tmp.cap-tmp.flow),t))>0) { tmp.flow+=a; e[v[o][i]^1].flow-=a; //存图方式 ans+=a; f-=a; if(f==0) //注意优化 break; } } return ans; //优化 } int dinci(int s,int t) { int ans=0; while(bfs(s,t)) { Del(cur,0); int tm=dfs(s,inf,t); ans+=tm; } return ans; } void MP_clear(int n) { for(int i=0;i<=n;i++) v[i].clear(); e.clear(); } int come[N],to[N]; int flow[400][N]; vector<pair<int ,int> > pp; int main() { //freopen("Input.txt","r",stdin); int n,m; while(~scanf("%d%d",&n,&m)) { Del(come,0); Del(to,0); Del(flow,0); int s=n+m,t = s+1; for(int i=0;i<m;i++) { int x; scanf("%d",&x); come[n+i]+=x; to[t]+=x; add_Node(n+i,t,inf); } for(int i=0;i<n;i++) { int cas,num; scanf("%d%d",&cas,&num); add_Node(s,i,num); for(int j=0;j<cas;j++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); pair<int,int> ts(i,x); pp.push_back(ts); flow[i][x]+=y; come[i]+=y; to[n+x]+=y; add_Node(i,n+x,z-y); //SB } } add_Node(t,s,inf); // int ss=t+1,tt=ss+1; int count=0; for(int i=0;i<=t;i++) { int cha = come[i]-to[i]; if(cha<0) { count+=-cha; add_Node(ss,i,-cha); } if(cha>0) add_Node(i,tt,cha); } int ans = dinci(ss,tt); if(ans != count) puts("-1"); else { //add_Node(t,s,0); printf("%d\n",dinci(s,t)); //SB for(int i=0;i<e.size();i++) { Node f = e[i]; if(i%2==0 && f.from<n){ flow[f.from][f.to-n]+=f.flow; //printf("%d %d %d %d\n",f.from,f.to,f.cap,f.flow); } } for(int i=0;i<pp.size();i++) { printf("%d\n",flow[pp[i].first][pp[i].second]); } } printf("\n"); MP_clear(tt); pp.clear(); } return 0; }
ZOJ Problem Set - 3229 Shoot the Bullet 【有上下界网络流+流量输出】
标签:algorithm 算法 网络流 有上下界网络流 dfs
原文地址:http://blog.csdn.net/y990041769/article/details/39779739