题意:
每个电脑需要P个组成部分,现有N的机器,每个机器都可以对电脑进行加工,不过加工的前提是某些部分已经存在,加工后会增加某些部分。且在单位时间内,每个机器的加工都有一个最大加工容量,求能得到的最大的流量,并且输出流经的所有路径。
思路:
最大流,EK算法。先建图,这里用邻接矩阵能比较简洁,由于每个机器(点)有权值,所以拆点,中间由与其权值想等的边连接,然后两两匹配,看是否能构成边。
代码:
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int Max = 205; const int eMax = 5000; const int inf = 0x3f3f3f3f; struct { int w, in[11], out[11]; }mac[Max]; struct { int v, ini_w, w, re, next; }edge[eMax]; int p, n, max_flow, num,k, edgeHead[Max],que[Max], pre[Max]; bool vis[Max]; void addedge(int u, int v, int w) { edge[k].v = v; edge[k].ini_w = edge[k].w = w; edge[k].next = edgeHead[u]; edge[k].re = k+1; edgeHead[u] = k ++; edge[k].v = u; edge[k].ini_w = edge[k].w = 0; edge[k].next = edgeHead[v]; edge[k].re = k-1; edgeHead[v] = k ++; } int bfs() { int head, tail, i, u, v; memset(vis, 0, sizeof(vis)); head = tail = 1; que[tail ++] = 0; vis[0] = true; while(tail > head){ u = que[head ++]; for(i = edgeHead[u]; i != 0; i = edge[i].next){ v = edge[i].v; if(!vis[v] && edge[i].w){ pre[v] = i; if(v == 2*n+1) return true; que[tail ++] = v; vis[v] = true; } } } return false; } void end() { int u, p, sum = inf; for(u = 2*n+1; u != 0; u = edge[edge[p].re].v){ p = pre[u]; sum = min(sum, edge[p].w); } for(u = 2*n+1; u != 0; u = edge[edge[p].re].v){ p = pre[u]; edge[p].w -= sum; edge[edge[p].re].w += sum; } max_flow += sum; } int main() { int i, j, u, m; bool flag; cin>>p>>n; for(k = 1, i = 1; i <= n; i ++) { cin>>mac[i].w; flag = true; for(j = 0; j < p; j ++) { cin>>mac[i].in[j]; if(mac[i].in[j] == 1) flag = false; // 这里要注意,0020也可以连源点,与汇点不同! } if(flag) addedge(0, i, inf); flag = true; for(j = 0; j < p; j ++) { cin>>mac[i].out[j]; if(mac[i].out[j] != 1) flag = false; } if(flag) addedge(n+i, 2*n+1, inf); } for(i = 1; i <= n; i ++) { addedge(i, n+i, mac[i].w); // 拆点。 for(j = 1; j <= n; j ++) { if(i == j) continue; flag = true; for(m = 0; m < p; m ++) if(mac[j].in[m] != 2 && mac[j].in[m] != mac[i].out[m]) { flag = false; break; } if(flag) addedge(n+i, j, inf); } } max_flow = 0, num = 0; while(bfs()) end(); for(u = n+1; u < 2*n+1 ; u ++) // 流经路径的输出,用邻接矩阵会更简洁。 for(i = edgeHead[u]; i != 0; i = edge[i].next) if(edge[i].v > 0 && edge[i].v <= n && edge[i].ini_w > edge[i].w) num ++; cout<<max_flow<<" "<<num<<endl; for(u = n+1; u < 2*n+1 ; u ++) for(i = edgeHead[u]; i != 0; i = edge[i].next) if(edge[i].v > 0 && edge[i].v <= n && edge[i].ini_w > edge[i].w) cout<<u-n<<" "<<edge[i].v<<" "<<edge[i].ini_w - edge[i].w<<endl; return 0; }