標籤:網路流 圖論
POJ 3436 ACM Computer Factory
連結:http://poj.org/problem?id=3436
題意:每台電腦有P部分,可以通過不同的機器來進行加工。有N台機器,每台機器用2 P +1 個整數來描述:Qi Si,1 Si,2 ... Si,p Di,1 Di,2. .. Di,p,其中Qi 指定了機器的效能,表示每小時加工的電腦數量。Si,j 為第j 部分的輸入規格,0表示該部分不能被加工過,1表示該部分必須被加工過,2表示都可以。Di,k 為第k 部分的輸出規格。0表示經過該機器不加工,1表示該機器加工該部分。1≤P≤10,1≤N≤50,1≤Qi≤10000。
思路:建立一個源點,只要每台機器的s部分沒有1,即從源點向其連邊,流量為該機器的效率。建立一個匯點,只要每台機器的D部分全部為1,則向匯點連邊,流量為機器的效率。如果某個機器的輸出部分符合某個機器的輸入部分,則兩者連邊,流量為min(Qi, Qj)。觀察發現如果 j 機器的輸入部分為2,這 i 機器輸出部分隨意,否則j的輸出部分必須與輸入部分相同。
PS:這道題也可以拆點來做,將每個機器的輸入部分和輸出部分分開,並連邊,流量為機器效率,然後不同機器之間匹配的話,流量就為INF。同時源點和匯點與機器連邊時,流量也為INF。
代碼:
/*ID: [email protected]PROG:LANG: C++*/#include<map>#include<set>#include<queue>#include<stack>#include<cmath>#include<cstdio>#include<vector>#include<string>#include<fstream>#include<cstring>#include<ctype.h>#include<iostream>#include<algorithm>using namespace std;#define LINF (1LL<<60)#define INF (1<<30)#define PI acos(-1.0)#define mem(a, b) memset(a, b, sizeof(a))#define rep(i, a, n) for (int i = a; i < n; i++)#define per(i, a, n) for (int i = n - 1; i >= a; i--)#define eps 1e-6#define debug puts("===============")#define pb push_back//#define mp make_pair#define all(x) (x).begin(),(x).end()#define fi first#define se second#define SZ(x) ((int)(x).size())#define POSIN(x,y) (0 <= (x) && (x) < n && 0 <= (y) && (y) < m)typedef long long ll;typedef unsigned long long ULL;const int maxn = 60;const int maxm = 20000;int st, ed, n;int P, N;int S[maxn][10], D[maxn][10], Q[maxn];struct node { int v; // vertex int cap; // capacity int flow; // current flow in this arc int nxt;} e[maxm * 2];int g[maxn], cnt;void add(int u, int v, int c) { e[++cnt].v = v; e[cnt].cap = c; e[cnt].flow = 0; e[cnt].nxt = g[u]; g[u] = cnt; e[++cnt].v = u; e[cnt].cap = 0; e[cnt].flow = 0; e[cnt].nxt = g[v]; g[v] = cnt;}bool check(int x, int y) { for (int i = 0; i < P; i++) if (S[y][i] != 2) { if (S[y][i] != D[x][i]) return false; } return true;}void init() { mem(g, 0); cnt = 1; scanf("%d%d", &P, &N); st = 0, ed = N + 1; int ok; for (int i = 1; i <= N; i++) { scanf("%d", Q + i); ok = 0; for (int j = 0; j < P; j++) { scanf("%d", S[i] + j); if (S[i][j] == 1) ok++; } if (!ok) add(st, i, Q[i]); ok = 0; for (int j = 0; j < P; j++) { scanf("%d", D[i] + j); if (D[i][j] == 1) ok++; } if (ok == P) add(i, ed, Q[i]); } for (int i = 1; i <= N; i++) { for (int j = i + 1; j <= N; j++) { if (check(i, j)) add(i, j, min(Q[i], Q[j])); if (check(j, i)) add(j, i, min(Q[i], Q[j])); } } n = N + 3;}int dist[maxn], numbs[maxn], q[maxn];void rev_bfs() { int font = 0, rear = 1; for (int i = 0; i <= n; i++) { //n為總點數 dist[i] = maxn; numbs[i] = 0; } q[font] = ed; dist[ed] = 0; numbs[0] = 1; while(font != rear) { int u = q[font++]; for (int i = g[u]; i; i = e[i].nxt) { if (e[i ^ 1].cap == 0 || dist[e[i].v] < maxn) continue; dist[e[i].v] = dist[u] + 1; ++numbs[dist[e[i].v]]; q[rear++] = e[i].v; } }}int maxflow() { rev_bfs(); int u, totalflow = 0; int curg[maxn], revpath[maxn]; for(int i = 0; i <= n; ++i) curg[i] = g[i]; u = st; while(dist[st] < n) { if(u == ed) { // find an augmenting path int augflow = INF; for(int i = st; i != ed; i = e[curg[i]].v) augflow = min(augflow, e[curg[i]].cap); for(int i = st; i != ed; i = e[curg[i]].v) { e[curg[i]].cap -= augflow; e[curg[i] ^ 1].cap += augflow; e[curg[i]].flow += augflow; e[curg[i] ^ 1].flow -= augflow; } totalflow += augflow; u = st; } int i; for(i = curg[u]; i; i = e[i].nxt) if(e[i].cap > 0 && dist[u] == dist[e[i].v] + 1) break; if(i) { // find an admissible arc, then Advance curg[u] = i; revpath[e[i].v] = i ^ 1; u = e[i].v; } else { // no admissible arc, then relabel this vertex if(0 == (--numbs[dist[u]])) break; // GAP cut, Important! curg[u] = g[u]; int mindist = n; for(int j = g[u]; j; j = e[j].nxt) if(e[j].cap > 0) mindist = min(mindist, dist[e[j].v]); dist[u] = mindist + 1; ++numbs[dist[u]]; if(u != st) u = e[revpath[u]].v; // Backtrack } } return totalflow;}int out[maxm][3], tot = 0;void get_out() { for (int u = 1; u < ed; u++) { for (int i = g[u]; i; i = e[i].nxt) { if (e[i].v != ed && e[i].flow > 0) { out[tot][0] = u; out[tot][1] = e[i].v; out[tot++][2] = e[i].flow; } } }}int main () { init(); printf("%d ", maxflow()); get_out(); printf("%d\n", tot); for (int i = 0; i < tot; i++) { printf("%d %d %d\n", out[i][0], out[i][1], out[i][2]); } return 0;}
POJ 3436 ACM Computer Factory (最大流 + 輸出路徑)