POJ-3436 ACM Computer Factory---最大流+拆点
题目链接:
https://vjudge.net/problem/POJ-3436
题目大意:
每台电脑有p个组成部分,有n个工厂加工电脑。每个工厂对于进入工厂的半成品的每个组成部分都有要求,由p个数字描述,0代表这个部分不能有,1代表这个部分必须有,2代表这个部分的有无无所谓。每个工厂的产出也不尽相同,也是由p个数字代表,0代表这个部分不存在,1代表这个部分存在。每个工厂都有一个最大加工量。给出这n个工厂的以上数据,求出最多能加工出多少台电脑。
解题思路:
这道题主要是如何建设出网络出来,每个工厂表示一个点
1、首先对每个点进行拆分,拆成i(输入部分)和n+i(输出部分),之间连接一条边,权值为这个点的加工量(拆点这个技巧是为了维护点的权值)
2、对每个点的输入部分(i),如果没有一,那就从超级源点s出发,连一条边到该点,权值为这个点的加工量。(因为只有全是0,或者是0或2没有1,那才是整个工厂的出发点)(此处不要忘记2的存在,一开始只把全是0的和超级源点s建边,后来想到只要没有1,都可以建边)
3、对于每个点的输出部分(n + i),如果全是1,说明已经建好,和超级汇点建边,权值为这个点的加工量
4、对于每个点的输出部分(n + i),只要满足其他点的输入部分,这两点之间可以建立边,权值设置成INF(这里设置成INF的目的是为了最后输出答案中的边,便于寻找这些边,只要权值为INF的边且流量不为0,那么这条边就可以输出)
然后就是从源点s到汇点t的最大流(传送门:最大流模板)
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int maxn = 100 + 10; 7 const int INF = 0x3f3f3f3f; 8 int n, m; 9 struct edge 10 { 11 int u, v, c, f; 12 edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){} 13 }; 14 vector<edge>e; 15 vector<int>Map[maxn]; 16 int a[maxn], p[maxn]; 17 void init(int n) 18 { 19 e.clear(); 20 for(int i = 0; i <= n; i++)Map[i].clear(); 21 } 22 void addedge(int u, int v, int c) 23 { 24 //cout<<u<<" "<<v<<" "<<c<<endl; 25 e.push_back(edge(u, v, c, 0)); 26 e.push_back(edge(v, u, 0, 0)); 27 int m = e.size(); 28 Map[u].push_back(m - 2); 29 Map[v].push_back(m - 1); 30 } 31 int Maxflow(int s, int t) 32 { 33 int flow = 0; 34 for(;;) 35 { 36 memset(a, 0, sizeof(a)); 37 queue<int>q; 38 q.push(s); 39 a[s] =INF; 40 while(!q.empty()) 41 { 42 int u = q.front(); 43 q.pop(); 44 for(int i = 0; i < Map[u].size(); i++) 45 { 46 edge& now = e[Map[u][i]]; 47 int v = now.v; 48 if(!a[v] && now.c > now.f)//还未流经并且边还有容量 49 { 50 p[v] = Map[u][i]; 51 a[v] = min(a[u], now.c - now.f); 52 q.push(v); 53 } 54 } 55 if(a[t])break;//已经到达汇点 56 } 57 if(!a[t])break;//已经没有增广路 58 for(int u = t; u != s; u = e[p[u]].u) 59 { 60 e[p[u]].f += a[t]; 61 e[p[u] ^ 1].f -= a[t]; 62 } 63 flow += a[t]; 64 } 65 return flow; 66 } 67 int cnt[maxn][maxn]; 68 vector<edge>ans; 69 int main() 70 { 71 cin >> m >> n; 72 for(int i = 1; i <= n; i++) 73 { 74 for(int j = 0; j <= 2 * m; j++)cin >> cnt[i][j]; 75 } 76 int s = 0, t = 2 * n + 1; 77 for(int i = 1; i <= n; i++) 78 { 79 int tot1 = 0, tot2 = 0; 80 for(int j = 1; j <= m; j++)tot1 += cnt[i][j] == 1 ? 1 : 0;//此处只要没有1,就可以和s建边 81 for(int j = m + 1; j <= 2 * m; j++)tot2 += cnt[i][j];//此处全为1就可以和t建边 82 addedge(i, i + n, cnt[i][0]); 83 if(tot1 == 0)addedge(s, i, cnt[i][0]); 84 if(tot2 == m)//和t建边之后没必要寻找其他点建边 85 { 86 addedge(i + n, t, cnt[i][0]); 87 continue; 88 } 89 for(int j = 1; j <= n; j++) 90 { 91 if(i == j)continue; 92 int flag = 1; 93 for(int k = 1; k <= m; k++) 94 { 95 if(cnt[j][k] == 0 && cnt[i][m + k] != 0)//第j个点的第k个值为0,说明不需要第k个元件,那么第i个点的第k原件输出只能为0 96 { 97 flag = 0; 98 break; 99 } 100 if(cnt[j][k] == 1 && cnt[i][m + k] != 1)//第j个点的第k个值为1,说明需要第k个元件,那么第i个点的第k原件输出只能为1 101 { 102 flag = 0; 103 break; 104 } 105 } 106 if(flag)addedge(i + n, j, INF);//ij可以建边,设置成INF 107 } 108 } 109 cout<<Maxflow(s, t)<<" "; 110 for(int i = 0; i < e.size(); i += 2)//此处+=2,是因为最大流有反向边 111 { 112 //cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].c<<" "<<e[i].f<<endl; 113 if(e[i].c == INF && e[i].f > 0) 114 { 115 ans.push_back(e[i]); 116 } 117 } 118 cout<<ans.size()<<endl; 119 for(int i = 0; i < ans.size(); i++) 120 { 121 cout<<ans[i].u - n<<" "<<ans[i].v<<" "<<ans[i].f<<endl; 122 } 123 }
越努力,越幸运