標籤:c++
題目連結:
poj3436
題意:
每台ACM 電腦包含P 個組件,當所有這些組件都準備齊全後,電腦就可以組裝了,組裝好以後就可以交給競賽隊伍使用了。電腦的生產過程是全自動的,通過N 台不同的機器來完成。每台機器從一台半成品電腦中去掉一些組件,並加入一些新的組件(去除一些組件在有的時候是必須的,因為電腦的組件不能以任意的順序組裝)。每台機器用它的效能(每小時組裝多少台電腦)、輸入/輸出規格來描述。
輸入規格描述了機器在組裝電腦時哪些組件必須準備好了。輸入規格是由P 個整數組成,每個整數代表一個組件,這些整數取值為0, 1 或2,其中0 表示該組件不應該已經準備好了,1表示該組件必須已經準備好了,2 表示該組件是否已經準備好了無關緊要。
輸出規格描述了該機器組裝的結果。輸出規格也是由P 個整數組成,每個整數取值為0 或1,其中0 代表該組件沒有生產好,1 代表該組件生產好了。
機器之間用傳輸速度非常快的流水線串連,組件在機器之間傳送所需的時間與機器生產時間相比是十分小的。
給出上述關於n台機器的描述,求一小時最多組成多少台電腦,並輸出資料流水線的路徑
解題思路:
題目已給出條件: 機器之間傳輸不需要時間,也就可以理解為流水線上每台機器的工作都是同步的,這樣就可以用網路流來解決了(單位時間問題)
解題的關鍵在於建圖.
話不多說,給出一張範例圖:
圖中紅色邊的容量應設為無窮大(單位時間運輸無限台電腦)
值得注意的是 圖中兩台機器的串連可以是雙向的(比如可以同時又B1->A2 ,B2->A1 )
關於路徑的輸出(找從n+1~2*n)開始的正向邊,有流則表示生產線經過這條路徑
代碼:
#include <iostream>#include <cstring>#include<cstdio>#define LL long long#include <queue>const int MAXN =205;const int MAXM=440020;const int INF=0x3f3f3f3f;using namespace std;struct Edge{ int from; int to,cap,flow,next;} edge[MAXM];int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];void init(){ tot=0; memset(head,-1,sizeof(head));}void addedge(int u,int v,int c,int f){ edge[tot]=(Edge) { u,v,c,f,head[u] }; head[u] = tot++; edge[tot]=(Edge) { v,u,c,c,head[v] }; head[v] = tot++;}int isap(int source,int sink,int N){ memset(gap,0,sizeof(gap)); memset(d,0,sizeof(d)); memcpy(cur,head,sizeof(head)); int top = 0,x = source,flow = 0; while(d[source] < N) { if(x == sink) { int Min = INF,inser=0; for(int i = 0; i < top; ++i) { if(Min > edge[p[i]].cap - edge[p[i]].flow) { Min = edge[p[i]].cap - edge[p[i]].flow; inser = i; } } for(int i = 0; i < top; ++i) { edge[p[i]].flow += Min; edge[p[i]^1].flow -= Min; } if(Min!=INF) flow += Min; top = inser; x = edge[p[top]^1].to; continue; } int ok = 0; for(int i = cur[x]; i != -1; i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && d[v]+1 == d[x]) { ok = 1; cur[x] = i; p[top++] = i; x = edge[i].to; break; } } if(!ok) { int Min = N; for(int i = head[x]; i != -1; i = edge[i].next) { if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min) { Min = d[edge[i].to]; cur[x] = i; } } if(--gap[d[x]] == 0) break; gap[d[x] = Min+1]++; if(x != source) x = edge[p[--top]^1].to; } } return flow;}int state[MAXN][2][10];int pp,n;int equall(int x,int y){ for(int i=0;i<pp;i++) if(state[y][0][i]+state[x][1][i]==1) return 0; return 1;}int main(){// freopen("in.txt","r",stdin); int w,flag1,flag2; while(~scanf("%d%d",&pp,&n)) { init(); memset(state,0,sizeof(state)); for(int i=1;i<=n;i++) { flag1=flag2=1; scanf("%d",&w); for(int j=0;j<pp;j++){ //全是0或2 則串連源點 scanf("%d",&state[i][0][j]); if(state[i][0][j]==1) flag1=0; } for(int j=0;j<pp;j++){ //全是1 則串連匯點 scanf("%d",&state[i][1][j]); if(state[i][1][j]==0||state[i][1][j]==2) flag2=0; } addedge(i,i+n,w,0); //拆點連自己 if(flag1==1) addedge(0,i,INF,0); if(flag2==1) addedge(i+n,2*n+1,INF,0); for(int j=1;j<i;j++){ if(equall(i,j)) addedge(n+i,j,INF,0); if(equall(j,i)) //注意不能是else if 兩個機器可以是雙向串連的 addedge(n+j,i,INF,0); } } printf("%d",isap(0,2*n+1,2*n+2)); int ans[400][3]; int ss=0; for(int i=n+1;i<=(n<<1);i++) //鄰接表找最大流中的邊 for(int j=head[i];j!=-1;j=edge[j].next) { if(edge[j].to==2*n+1||edge[j].to==i-n) continue; if(edge[j].flow>0){ ans[ss][0]=edge[j].from-n; ans[ss][1]=edge[j].to; ans[ss++][2]=edge[j].flow; } } printf(" %d\n",ss); for(int i=0;i<ss;i++) printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]); } return 0;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
poj 3436 ACM Computer Factory 最大流拆點+輸出路徑