ZOJ 3229 Shoot the Bullet(有源汇上下界最大流)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442

题目大意:

一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给给定的C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照;否则输出-1。

解题思路:

有源汇带上下界的最大流,我也是第一次写。

说下建图:

①源点S到第i天流量为D[i]的边(上界为D[i],下界为0)

②第i天向女孩连流量为r-l的边(上界为r,下界为l)

③女孩向汇点T连流量为G[i]的边(上界为INF,下界为G[i])

④汇点向源点连流量为INF的边,使其变成无源汇图。(上界为INF,下界为0)

⑤out[i]为i点的出边下界和,in[i]为i点的入边下界和,若in[i]-out[i]>0,则从附加源点SS向i连流量为in[i]-out[i]的边,

若in[i]-out[i]<0,则从i点向附加汇点TT连流量为out[i]-in[i]的边。

具体求法,就是先求出改图是否存在可行流,即求有源汇上下界可行流,通过从T->连流量为INF的边即可将图变为无源汇图,这样就可以转换为无源汇上下界可行流求解。

若存在可行流,则再求一次S->T的最大流即为答案。

(这句话从网上找的)

为什么呢?因为第一次SS->TT只是求得所有满足下界的流量,而残留网络(S,T)路上还有许多自由流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的ans=(第一次流满下界的流+第二次能流通的自由流)。

说起来ZOJ真是害我不浅啊,今天刚开始写上下界的题目,ZOJ 2314 low数组开小了一直TLE。。。。 然后这题忘记输出空行一直WA。。。 然后我每次都以为是自己写的问题debug好几个小时,难受啊。

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<vector>
  8 #define LL long long
  9 #define pii pair<int,int>
 10 #define pll pair<long long,long long>
 11 #define rep(i,a,b) for(int i=a;i<=b;i++)
 12 #define per(i,a,b) for(int i=a;i>=b;i--)
 13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
 14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
 15 #define bugc(_) cout << (#_) << " = " << (_) << endl;
 16 using namespace std;
 17 const int N=2e3+5;
 18 const int M=1e5+5;
 19 const int INF=0x3f3f3f3f;
 20 
 21 struct node{
 22     int to,next,flow;
 23 }edge[M*2];
 24 
 25 int cnt,st,en;
 26 int head[N],dep[N],out[N],in[N],low[M],G[N],D[N];
 27 
 28 void init(){
 29     cnt=2;
 30     memset(head,0,sizeof(head));
 31     memset(out,0,sizeof(out));
 32     memset(in,0,sizeof(in));
 33 }
 34 
 35 void link(int u,int v,int flow){
 36     edge[cnt]=node{v,head[u],flow};
 37     head[u]=cnt++;
 38     edge[cnt]=node{u,head[v],0};
 39     head[v]=cnt++;
 40 }
 41 
 42 int bfs(){
 43     memset(dep,0,sizeof(dep));
 44     dep[st]=1;
 45     queue<int>q;
 46     q.push(st);
 47     while(!q.empty()){
 48         int u=q.front();
 49         q.pop();
 50         for(int i=head[u];i;i=edge[i].next){
 51             node t=edge[i];
 52             if(t.flow&&!dep[t.to]){
 53                 dep[t.to]=dep[u]+1;
 54                 q.push(t.to);
 55             }
 56         }
 57     }
 58     return dep[en];
 59 }
 60 
 61 int dfs(int u,int fl){
 62     if(en==u) return fl;
 63     int tmp=0;
 64     for(int i=head[u];i&&fl;i=edge[i].next){
 65         node &t=edge[i];
 66         if(t.flow&&dep[t.to]==dep[u]+1){
 67             int x=dfs(t.to,min(t.flow,fl));
 68             if(x>0){
 69                 tmp+=x;
 70                 fl-=x;
 71                 t.flow-=x;
 72                 edge[i^1].flow+=x;
 73             }
 74         }
 75     }
 76     if(!tmp) dep[u]=-2;
 77     return tmp;
 78 }
 79 
 80 int dinic(int S,int T){
 81     st=S,en=T;
 82     int ans=0;
 83     while(bfs()){
 84         while(int d=dfs(st,INF))
 85             ans+=d;
 86     }
 87     return ans;
 88 }
 89 
 90 int main(){
 91     int n,m;
 92     while(~scanf("%d%d",&n,&m)){
 93         init();
 94         int S=0,T=n+m+1,SS=n+m+2,TT=n+m+3;
 95         for(int i=1;i<=m;i++) scanf("%d",&G[i]);
 96         int num=0,sum=0;
 97         for(int i=1;i<=n;i++){
 98             int C;
 99             scanf("%d%d",&C,&D[i]);
100             for(int j=1;j<=C;j++){
101                 int id,l,r;
102                 scanf("%d%d%d",&id,&l,&r);
103                 id++;
104                 link(i,id+n,r-l);
105                 low[++num]=l;
106                 out[i]+=l;
107                 in[id+n]+=l;
108             }
109         }
110         link(T,S,INF);
111         for(int i=1;i<=n;i++){
112             link(S,i,D[i]);     //D[i]是上限,下限为0,因为每天最多拍D[i]张照片 
113         }
114         for(int i=1;i<=m;i++){
115             link(i+n,T,INF);//G[i]是下限,因为每个人至少要G[i]张照片 
116             in[T]+=G[i];
117             out[i+n]+=G[i];
118         }
119         for(int i=0;i<=n+m+1;i++){
120             int tmp=in[i]-out[i];
121             if(tmp>0)    link(SS,i,tmp),sum+=tmp;
122             else if(tmp<0)    link(i,TT,-tmp);
123         }
124         int ans=dinic(SS,TT);
125         if(ans==sum){
126             ans=dinic(S,T);
127             printf("%d\n",ans);
128             for(int i=1;i<=num;i++){
129                 printf("%d\n",edge[i*2+1].flow+low[i]);
130             }
131         }
132         else
133             puts("-1");
134         puts("");
135     }
136     return 0;
137 }

 

posted @ 2018-11-02 11:29  Yeader  阅读(202)  评论(0编辑  收藏  举报