poj3436 ACM Computer Factory
题意:每台电脑有p个零件,有n台加工电脑的机器,每台机器可以处理某一种未加工完成的电脑,给出该机器加工前电脑必须所拥有的零件和加工后该电脑所拥有的零件,以及每小时可以加工的数量c[i],问你这些机器每小时最多可以同时加工成多少台完整的电脑。
对于每台机器i(1<=i<=n),拆成两个点i,i+n,连一条边i->i+n,其容量为c[i],设一个超级源点0和超级汇点$2n+1$,对于初始零件为0的电脑i,连一条边0->i,对于加工后零件为n的定案哦,连一条边$i+n->2
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int MAXN=1000,MAXM=100000,inf=1e9; int in[505][12],out[505][12],V[55]; int s[505][505]; bool mp[55][55]; int p,n; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],dis[MAXN],gap[MAXN],N,sz; void init(int _n) { N=_n,sz=0; memset(G,-1,sizeof(G[0])*N); } void link(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it;h<t;++h) { for (u=Q[h],it=G[u];~it;it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u];~it&&ret<low;it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; //if(u!=0&&v!=2*n+1&&v!=u+n) s[u-n][v]+=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G[0])*N); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } bool pan(int x,int y){ for(int i=1;i<=p;i++){ if(in[y][i]==2) continue; if(in[y][i]!=out[x][i]) return false; } return true; } int main(){ scanf("%d%d",&p,&n); for(int i=1;i<=n;i++){ scanf("%d",&V[i]); for(int j=1;j<=p;j++) scanf("%d",&in[i][j]); for(int j=1;j<=p;j++) scanf("%d",&out[i][j]); } init(n*2+2); // cout<<-2<<endl; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(i!=j&&pan(i,j)){ mp[i][j]=1; // cout<<i<<" "<<j<<-1<<endl; } } for(int i=1;i<=n;i++) link(i,i+n,V[i]); for(int i=1;i<=n;i++){ int j; for(j=1;j<=p;j++){ if(in[i][j]==1) break; } if(j>p) link(0,i,V[i]); } for(int i=n+1;i<=n*2;i++){ int j; for(j=1;j<=p;j++){ if(out[i-n][j]!=1) break; } if(j>p) link(i,n*2+1,V[i-n]); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j){ if(mp[i][j]==1) link(i+n,j,V[i]); } printf("%d",dinic(0,n*2+1)); int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(s[i][j]>0) ans++; } printf(" %d\n",ans); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(s[i][j]>0) printf("%d %d %d\n",i,j,s[i][j]); } }
poj1087 A Plug for UNIX
这题意真的有毒。。。
题意:已知有n个插座,m个需要充电的电器,每个电器有一种对应的插座,有k种适配器,每种适配器有无限个,适配器可以将插座j改为插座i(j先输入),问你最少有多少个·电器没有对应的插座可以插
设一个超级源点s和超级汇点t,对于每个插座,从s连一条边到该插座,容量为1,从所有电器连一条边到汇点,容量为1,从所有适配器的接入插座到输出插座连一条容量为无穷的边,求一下最大流即可,输出n-最大流
#include<iostream> #include<map> #include<cstring> #include<algorithm> #include<queue> #include<cstdio> using namespace std; map<string,int> mp; queue<int> qs,qt; int X=0; int q[1000][1000]; const int MAXN=10000,MAXM=10000,inf=1e9; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz; void init(int _n) { N=_n,sz=0; memset(G,-1,sizeof(G[0])*N); } void link(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it;h<t;++h) { for (u=Q[h],it=G[u];~it;it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u];~it&&ret<low;it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G[0])*N); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } int main(){ int n,m,k; sz=0; scanf("%d",&n); memset(G,-1,sizeof(G[0])*10000); getchar(); for(int i=0;i<n;i++){ char s[35]; scanf("%s",s); int z=mp[s]; if(z==0){ mp[s]=++X; qs.push(X); } else { qs.push(z); } } scanf("%d",&m); getchar(); for(int i=0;i<m;i++){ char s1[30],s2[30]; scanf("%s%s",s1,s2); int z=mp[s2]; if(z==0){ mp[s2]=++X; qt.push(X); } else qt.push(z); } scanf("%d",&k); getchar(); for(int i=0;i<k;i++){ char s1[30],s2[30]; scanf("%s%s",s1,s2); if(mp[s1]==0) mp[s1]=++X; if(mp[s2]==0) mp[s2]=++X; int a=mp[s1],b=mp[s2]; link(b,a,inf); } while(!qs.empty()){ link(0,qs.front(),1); qs.pop(); } while(!qt.empty()){ link(qt.front(),X+1,1); qt.pop(); } N=X+2; printf("%d\n",m-dinic(0,X+1)); }
poj2516 Minimum Cost 最小费用最大流
题意:有n个收货商和m个供应商以及k种产品,对于每种产品,收货商有一个需求量,供货商有一个生产量,且从供应商送到收货商有一个花费,问你如何调配,使得每个收获商都能恰好获得自己所需要的产品的前提下总费用最小(n,m,k<=100)
每种产品都不互相影响,故求k次最小费用最大流即可
对于每种产品,先判断供应商的总和是否足够收货商的总和;建立一个超级源点s和超级汇点t,从s到每个供货商建立一条边,容量为供应商所能产生该商品的数量,费用为0,从每个供应商到每个收货商建立一条边,容量为供应商所能产生该商品的数量,费用为运输费用,从每个收货商到t连一条边,容量为收货商所需要的产品数量,费用为0,求k次最小费用最大流即可
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int need[55][55]; int out[55][55]; int val[55][55][55]; const int inf=~0U>>2,N=2000,M=20000; int u[M],v[M],c[M],co[M],nxt[M],t=1,S,T,l,r,q[M],g[N],f[N],d[N]; bool in[N]; void add(int x,int y,int z,int zo){ u[++t]=x;v[t]=y;c[t]=z;co[t]=zo;nxt[t]=g[x];g[x]=t; u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;nxt[t]=g[y];g[y]=t; } void init(int n){ t=1; l=0;r=0; for(int i=0;i<=n;i++) c[i]=g[i]=q[i]=in[i]=nxt[i]=co[i]=u[i]=v[i]=f[i]=0; } bool spfa(){ int x,i; for(i=1;i<=T;i++)d[i]=inf,in[i]=0; d[S]=0;in[S]=1;l=r=M>>1;q[l]=S; while(l<=r){ int x=q[l++]; if(x==T)continue; for(i=g[x];i;i=nxt[i]) if(c[i]&&co[i]+d[x]<d[v[i]]){ d[v[i]]=co[i]+d[x];f[v[i]]=i; if(!in[v[i]]){ in[v[i]]=1; if(d[v[i]]<d[q[l]]) q[--l]=v[i]; else q[++r]=v[i]; } } in[x]=0; } return d[T]<inf; } int min_cost_flow(int a,int b){ t=1; int i,tmp; S=a,T=b; int ans=0; //cout<<-1<<endl; while(spfa()){ for(tmp=inf,i=T;i!=S;i=u[f[i]])if(tmp>c[f[i]])tmp=c[f[i]]; for(ans+=d[i=T]*tmp;i!=S;i=u[f[i]])c[f[i]]-=tmp,c[f[i]^1]+=tmp; } return ans; } int summ[55],sumn[55]; int main(){ int n,m,k; while(scanf("%d%d%d",&n,&m,&k)&&(n+m+k)){ for(int i=1;i<=k;i++) sumn[i]=summ[i]=0; for(int i=1;i<=n;i++) for(int j=1;j<=k;j++){ scanf("%d",&need[i][j]); sumn[j]+=need[i][j]; } for(int i=1;i<=m;i++) for(int j=1;j<=k;j++){ scanf("%d",&out[i][j]); summ[j]+=out[i][j]; } for(int x=1;x<=k;x++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&val[x][j][i]); bool f=1; for(int i=1;i<=k;i++){ if(sumn[i]>summ[i]){ f=0; break; } } if(!f){ printf("-1\n"); continue; } //cout<<-1<<endl; int ans=0; for(int i=1;i<=k;i++){ init(n+m+2); for(int j=1;j<=m;j++) add(0,j,out[j][i],0); for(int j=m+1;j<=n+m;j++) add(j,n+m+1,need[j-m][i],0); for(int p=1;p<=m;p++) for(int q=1;q<=n;q++) add(p,q+m,out[p][i],val[i][p][q]); ans+=min_cost_flow(0,n+m+1); } printf("%d\n",ans); } }
poj1459 Power Network 最大流
有p(p<=100)个发电站可以产生电,有c(c<=100)个消费者,可以消费电量,还有一些运输系统,只传送电,已知每个发电站可以产生的电量以,和某些点到另一些点的运输量,问你最大消费量
建立一个超级源点s和超级汇点t,从s到所有的发电站连一条边,容量为发电站产生的电量,从所有的消费者到t连一条边,容量为消费者消费的量,求最大流即可
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int MAXN=100000,MAXM=100000,inf=1e9; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz; void init(int _n) { N=_n,sz=0; memset(G,-1,sizeof(G[0])*N); } void link(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it;h<t;++h) { for (u=Q[h],it=G[u];~it;it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u];~it&&ret<low;it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G[0])*N); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main(){ int n,x,y,m; while(scanf("%d%d%d%d",&n,&x,&y,&m)!=EOF){ getchar(); // cout<<n<<x<<y<<m<<endl; init(n+2); for(int i=1;i<=m;i++){ int a,b,c; a=read();b=read();c=read(); link(a+1,b+1,c); // cout<<a<<b<<c<<endl; } for(int i=1;i<=x;i++){ int a,b; a=read();b=read(); link(0,a+1,b); } for(int i=1;i<=y;i++){ int a,b; a=read();b=read(); link(a+1,n+1,b); } printf("%d\n",dinic(0,n+1)); } }