码迷,mamicode.com
首页 > 其他好文 > 详细

zoj 3229 有源汇有上下界的最大流模板题

时间:2016-02-26 22:04:27      阅读:278      评论:0      收藏:0      [点我收藏+]

标签:

/*坑啊,pe的程序在zoj上原来是wa。

题目大意:一个屌丝给m个女神拍照。计划拍照n天,每一天屌丝最多个C个女神拍照,每天拍照数不能超过D张,并且给每一个女神i拍照有数量限制[Li,Ri], 对于每一个女神n天的拍照总和不能超过Gi,假设有解求屌丝最多能拍多少张照,并求每天给相应女神拍多少张照;否则输出-1。 解题思路:增设一源点st,汇点sd。st到第i天连一条上界为Di下界为0的边,每一个女神到汇点连一条下界为Gi上界为oo的边,对于每一天,当天到第i个女孩连一条[Li。Ri]的边。 建图模型:源点s。终点d。超级源点ss,超级终点dd。首先推断是否存在满足全部边上下界的可行流。方法能够转化成无源汇有上下界的可行流问题。

怎么转换呢? 增设一条从d到s没有下界容量为无穷的边,那么原图就变成了一个无源汇的循环流图。接下来的事情一样,超级源点ss连i(du[i]>0),i连超级汇点(du[i]<0), 对(ss。dd)进行一次最大流。当maxflow等于全部(du[]>0)之和时,有可行流。否则没有。 当有可行流时。删除超级源点ss和超级终点dd,再对(s。d)进行一次最大流,此时得到的maxflow则为题目的解。为什么呢? 由于第一次maxflow()仅仅是求得全部满足下界的流量,而残留网络(s,d)路上还有很多自由流(没有和超级源点和超级汇点连接的边)没有流满, 全部终于得到的maxflow=(第一次流满下界的流+第二次能流通的自由流)。

*/ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define N 1500 #define ii 400000 #define inf 0x3fffffff struct node { int u,v,w,f,next; }bian[ii*2]; int head[N],yong,dis[N],work[N]; void init(){ yong=0; memset(head,-1,sizeof(head)); } void addbian(int u,int v,int w,int f) { bian[yong].u=u; bian[yong].v=v; bian[yong].w=w; bian[yong].f=f; bian[yong].next=head[u]; head[u]=yong++; } void add(int u,int v,int w,int f) { addbian(u,v,w,f); addbian(v,u,0,f); } int min(int a,int b) { return a<b?a:b; } int bfs(int s,int t) { memset(dis,-1,sizeof(dis)); queue<int>q; q.push(s); dis[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=bian[i].next) { int v=bian[i].v; if(bian[i].w&&dis[v]==-1) { dis[v]=dis[u]+1; q.push(v); if(v==t) return 1; } } } return 0; } int dfs(int s,int limit,int t) { if(s==t)return limit; for(int &i=work[s];i!=-1;i=bian[i].next) { int v=bian[i].v; if(bian[i].w&&dis[v]==dis[s]+1) { int tt=dfs(v,min(limit,bian[i].w),t); if(tt) { bian[i].w-=tt; bian[i^1].w+=tt; return tt; } } } return 0; } int dinic(int s,int t) { int ans=0; while(bfs(s,t)) { memcpy(work,head,sizeof(head)); while(int tt=dfs(s,inf,t)) ans+=tt; } return ans; } int main() { int n,m,i,j,k,s,t,S,T,a,b,d,index[ii],id,suma,w[N]; while(scanf("%d%d",&n,&m)!=EOF) { init(); s=0;t=m+n+1; S=t+1;T=S+1; memset(w,0,sizeof(w)); for(i=1;i<=m;i++) { scanf("%d",&a); w[t]+=a; w[i+n]-=a; add(i+n,t,inf-a,0); } id=0; for(i=1;i<=n;i++) { scanf("%d%d",&a,&b); add(s,i,b,b); while(a--) { scanf("%d%d%d",&j,&k,&d); j++; index[id++]=yong; w[i]-=k; w[j+n]+=k; add(i,j+n,d-k,d); } } add(t,s,inf,inf); suma=0; for(i=s;i<=t;i++) { if(w[i]>0) { suma+=w[i]; add(S,i,w[i],0); } else add(i,T,-w[i],0); } int f=dinic(S,T); if(f==suma) { head[S]=head[T]=-1; printf("%d\n",dinic(s,t)); for(i=0;i<id;i++) printf("%d\n",bian[index[i]].f-bian[index[i]].w); } else printf("-1\n"); printf("\n"); } return 0; }


zoj 3229 有源汇有上下界的最大流模板题

标签:

原文地址:http://www.cnblogs.com/mengfanrong/p/5221698.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!