題目連接:https://vjudge.net/problem/POJ-3436node
Sample input 1
3 4
15 0 0 0 0 1 0
10 0 0 0 0 1 1
30 0 1 2 1 1 1
3 0 2 1 1 1 1
題目:P —— 一臺電腦由p個零件組成ios
N —— 工廠有n臺加工組裝電腦的機器數組
Q —— i-th機器每單位時間能工做的數量
當每一個未成品須要放入某個機器進一步加工的時候,它須要知足這臺機器能正常工做的前提,
即它必須知足某些零件已經組裝好了。
樣例1: 前p個數字表示,進入i-th臺機器,必須知足這些條件(0表示這個零件不能被安裝 1表示這個零件必須被安裝 2表示這個零件有無被安裝無影響)
後p個數字表示,某個未成品被i-th臺機器加工完成後,知足了這些條件(0表示這個零件沒被安裝 1表示這個零件被安裝了)
問:怎麼安排機器工做方案,能使得工做效率最大化,安排狀況有不少,輸出一種便可。
思路:比較清楚,一個超級源點,一個超級匯點,一臺機器須要拆成入點和出點,一臺機器的入點和出點流量爲該機器單位時間的工做量,其餘點與點之間的流量就是INF了。
重點就是哪些邊能創建起來比較麻煩,圖建好了,跑一個Dinic就OK了。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <queue> 5 #include <vector> 6 using namespace std; 7 8 const int N = 110,INF = (int)1e9; 9 int p,n,tot; 10 int G[N][N],head[N],lev[N]; 11 queue<int > que; 12 struct info{ 13 int in[20],out[20]; 14 int cap; 15 }info[N];//存機器的信息 16 struct node{ 17 int to,nxt,flow; 18 }e[N*N]; 19 20 void init_main(){ 21 for(int i = 1; i <= n; ++i) 22 for(int j = 1; j <= n; ++j) G[i][j] = 0; 23 24 for(int i = 0; i <= 2*n+1; ++i) head[i] = -1; tot = 0; 25 } 26 27 void init_bfs(){ 28 for(int i = 1; i <= 2*n+1; ++i) lev[i] = 0; 29 while(!que.empty()) que.pop(); 30 } 31 32 inline void add(int u,int v,int flow){ 33 e[tot].to = v; 34 e[tot].flow = flow; 35 e[tot].nxt = head[u]; 36 head[u] = tot++; 37 } 38 39 //是否可連邊 40 inline bool check(int x,int y){ 41 for(int i = 1; i <= p; ++i){ 42 if(info[y].in[i] == 2) continue; 43 if(info[x].out[i] != info[y].in[i]) return false; 44 } 45 return true; 46 } 47 48 //建邊 49 void rebuild(){ 50 for(int i = 1; i <= n; ++i){ 51 if(check(0,i)){ 52 add(0,i,INF); add(i,0,0); 53 } 54 if(check(i,2*n+1)){ 55 add(i+n,2*n+1,INF); add(2*n+1,i+n,0); 56 } 57 } 58 for(int i = 1; i <= n; ++i){ 59 for(int j = 1; j <= n; ++j){ 60 if(i == j){ 61 add(i,i+n,info[i].cap); add(i+n,i,0); 62 } 63 else if(check(i,j)){ 64 add(i+n,j,INF); add(j,i+n,0); 65 } 66 } 67 } 68 } 69 70 int dfs(int now,int flow,int t){ 71 if(now == t) return flow; 72 int to,sum = 0,tmp = 0; 73 for(int o = head[now]; ~o; o = e[o].nxt){ 74 to = e[o].to; 75 if((lev[to] == lev[now] +1) && e[o].flow && (tmp = dfs(to,min(flow - sum, e[o].flow),t))){ 76 //須要的路徑流量 G數組來存機器之間的聯繫 77 if(now > n && now < 2*n+1 && to != 2*n+1){ 78 G[now-n][to] += tmp; 79 } 80 e[o].flow -= tmp; 81 e[o^1].flow += tmp; 82 if((sum += tmp) == flow) return sum; 83 } 84 } 85 return sum; 86 } 87 88 bool bfs(int s,int t){ 89 init_bfs(); 90 que.push(0); 91 while(!que.empty()){ 92 int now = que.front(); que.pop(); 93 for(int o = head[now]; ~o; o = e[o].nxt){ 94 int to = e[o].to; 95 if(!lev[to] && e[o].flow){ 96 lev[to] = lev[now] + 1; 97 que.push(to); 98 } 99 } 100 } 101 if(lev[t]) return true; 102 else return false; 103 } 104 105 int mf(int s,int t){ 106 int max_flow = 0; 107 while(bfs(s,t)){ 108 max_flow += dfs(s,INF,t); 109 //cout << "max_flow " << max_flow << endl; 110 } 111 return max_flow; 112 } 113 114 int main(){ 115 116 while(~scanf("%d%d",&p,&n)){ 117 init_main(); 118 //讀入信息 0超級源點 2*n+1超級匯點 119 for(int i = 1; i <= n; ++i){ 120 scanf("%d",&info[i].cap); 121 for(int j = 1; j <= p; ++j) scanf("%d",&info[i].in[j]); 122 for(int j = 1; j <= p; ++j) scanf("%d",&info[i].out[j]); 123 } 124 info[0].cap = INF; info[2*n+1].cap = INF; 125 for(int i = 1; i <= p; ++i){ 126 info[0].out[i] = 0; 127 info[2*n+1].in[i] = 1; 128 } 129 //建圖 130 rebuild(); 131 //Dinic 132 int _mf = mf(0,2*n+1),line = 0; 133 //統計須要的聯繫數量 134 for(int i = 1; i <= n; ++i){ 135 for(int j = 1; j <= n; ++j){ 136 if(G[i][j]) ++line; 137 } 138 } 139 printf("%d %d\n",_mf,line); 140 //輸出聯繫 141 for(int i = 1; i <= n; ++i){ 142 for(int j = 1; j <= n; ++j){ 143 if(G[i][j]) printf("%d %d %d\n",i,j,G[i][j]); 144 } 145 } 146 } 147 148 return 0; 149 }