题意:每台电脑共有p种零件,现在有n台机器,给出n台机器每台需要的一些种类零件当原料(0代表不需要,1代表必须要,2代表可有可无)和输出的产品零件。问怎么安排生产线使生产出来零件可以组装的电脑最多。
思路:如果机器的原材料什么都不需要的话就可以当源点,如果机器输出的零件种类为p就可以当汇点。刚开始想复杂了(1 0 1 可以同时跟1 0 0和0 0 1相连),这题只有当一台机器的输出格式跟另一台的输入格式一样时才可以相连,不能有多余的零件产生。最后想想如果不是这样的话,2代表的可有可无就没意义了。当p=3时,输出1 0 1不能跟1 0 0相连但可以跟1 0 2相连。
#include<stdio.h> #include<string.h> const int N=100; const int inf=0x3fffffff; int gap[N],dis[N],head[N],num,start,end,ans,pp[N*N]; struct edge { int st,ed,flow,next; }e[N*N],ee[N*N]; void addedge(int x,int y,int w) { ee[num].st=x;ee[num].ed=y;ee[num].flow=w; e[num].st=x;e[num].ed=y;e[num].flow=w;e[num].next=head[x];head[x]=num++; e[num].st=y;e[num].ed=x;e[num].flow=0;e[num].next=head[y];head[y]=num++; } struct node { int in[11],out[11],w; }p[N]; int dfs(int u,int minflow) { if(u==end)return minflow; int i,flow=0,f,v,min_dis=ans-1; for(i=head[u];i!=-1;i=e[i].next) { if(e[i].flow<=0)continue; v=e[i].ed; if(dis[v]+1==dis[u]) { f=dfs(v,e[i].flow>minflow-flow?minflow-flow:e[i].flow); e[i].flow-=f; e[i^1].flow+=f; flow+=f; if(flow==minflow)break; if(dis[start]>=ans)return flow; } min_dis=min_dis>dis[v]?dis[v]:min_dis; } if(flow==0) { if(--gap[dis[u]]==0) dis[start]=ans; dis[u]=min_dis+1; gap[dis[u]]++; } return flow; } int isap() { int maxflow=0; memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); gap[0]=ans; while(dis[start]<ans) maxflow+=dfs(start,inf); return maxflow; } int main() { int i,n,m,j,flag,k,sum,maxflow; while(scanf("%d%d",&m,&n)!=-1) { memset(head,-1,sizeof(head)); start=0,end=n+1;ans=end+1;num=0; for(i=1;i<=n;i++) { flag=0; scanf("%d",&p[i].w); for(j=0;j<m;j++) { scanf("%d",&p[i].in[j]); if(p[i].in[j]==1) flag=1; } if(flag==0)//如果什么原料都不要就与超级源点相连 addedge(start,i,p[i].w); flag=0; for(j=0;j<m;j++) { scanf("%d",&p[i].out[j]); if(p[i].out[j]==0) flag=1; } if(flag==0)//如果能生产所有的零件跟汇点相连 addedge(i,end,p[i].w); } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(j==i)continue; for(k=0;k<m;k++) { if(p[j].in[k]==2)continue;//可有可无的时候,不管p[i].out[k]为何值都可以 if(p[i].out[k]==p[j].in[k])continue;//i的输出要跟j的输入一样 break; } if(k==m) addedge(i,j,p[i].w); } } maxflow=isap(); sum=0; for(i=0;i<num;i+=2) { if(e[i].st==start||e[i].ed==end)continue; if(e[i].flow<ee[i].flow)//如果边的流量变小的,就有流量走过 pp[sum++]=i; } printf("%d %d\n",maxflow,sum); for(j=0;j<sum;j++) { i=pp[j]; printf("%d %d %d\n",e[i].st,e[i].ed,ee[i].flow-e[i].flow); } } return 0; }