[题目链接](http://poj.org/problem?id=3436) 题意: 题意确实难读。 首先给出p,n 两个数 表示有p台机床来组装电脑,每台电脑有n个零件需要组装 接着p行,每行描述一台机床 共2*n+1个数字, 第一个数字表示每单位时间该机床能处理多少未完成品 接下来n个数字表示该机床能接受的未完成品类型 0表示该零件不能存在 1表示该零件必须存在 2表示该零件可存在 最后n个数字表示处理后 未完成品是什么样的。 问怎么样用这些机床构成生产线 使得单位产量最大 最后要你打印路径。 写的第一道不是那么裸的网络流题目,因为要打印路径 所以不能直接套模板。 先按老套路,拆点建边。 建好图之后,跑一遍网络流。 然后再遍历一遍原来的边,如果这条边有用的话,那他的流量肯定小于容量,把这些边全部找出来就行。#include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<cstdio> #define For(a,b,c) for(a=b;a<=c;a++) #include<queue> using namespace std; int n,m; int val[300]; const int inf = 0x3f3f3f3f; const int MX=300 ; const int MXE= 4 * MX * MX; struct Edge { int u,v, w, nxt; }; struct MaxFlow { Edge edge[MXE]; int tot, num, s, t; int head[MX]; void init() { memset(head, -1, sizeof(head)); tot = 0; } void add(int u, int v, int w) { edge[tot].u = u; edge[tot].v = v; edge[tot].w = w; edge[tot].nxt = head[u]; head[u] = tot++; edge[tot].u = v; edge[tot].v = u; edge[tot].w = 0; edge[tot].nxt = head[v]; head[v] = tot++; } int d[MX], vis[MX], gap[MX]; void bfs() { memset(d, 0, sizeof(d)); memset(gap, 0, sizeof(gap)); memset(vis, 0, sizeof(vis)); queue<int>q; q.push(t); vis[t] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; ~i; i = edge[i].nxt) { int v = edge[i].v; if (!vis[v]) { d[v] = d[u] + 1; gap[d[v]]++; q.push(v); vis[v] = 1; } } } } int last[MX]; int dfs(int u, int f) { if (u == t) return f; int sap = 0; for (int i = last[u]; ~i; i = edge[i].nxt) { int v = edge[i].v; if (edge[i].w > 0 && d[u] == d[v] + 1) { last[u] = i; int tmp = dfs(v, min(f - sap, edge[i].w)); edge[i].w -= tmp; edge[i ^ 1].w += tmp; sap += tmp; if (sap == f) return sap; } } if (d[s] >= num) return sap; if (!(--gap[d[u]])) d[s] = num; ++gap[++d[u]]; last[u] = head[u]; return sap; } int solve(int st, int ed, int n) { int flow = 0; num = n; s = st; t = ed; bfs(); memcpy(last, head, sizeof(head)); while (d[s] < num) flow += dfs(s, inf); return flow; } void slove(vector<Edge> &V) { for(int i=0;i<tot;i+=2){ if(edge[i].u>m) continue; if(edge[i].w<val[edge[i].u]){ Edge cnt; int sum=val[edge[i].u]-edge[i].w; for(int j=head[edge[i].u+m];j!=-1;j=edge[j].nxt){ int v=edge[j].v; if(v==2*m+1) continue;// 连向超级汇点的边要跳过 if(edge[j].w<20000) continue;// 反向边跳过 cnt.u=edge[i].u; if(edge[j].w<inf){ cnt.v=edge[j].v; cnt.w=inf-edge[j].w; V.push_back(cnt); } } } } } } F; int str[300][2][50]; bool check1(int a[],int len) { //for(int i=1; i<=len; i++)cout<<a[i]<<" "; //puts(""); for(int i=1; i<=len; i++) { if(a[i]==1) return false; } return true; } bool check2(int a[],int len) { for(int i=1; i<=len; i++) { if(a[i]!=1) return false; } return true; } bool cmp(int a[],int b[],int len) { //for(int i=1; i<=len; i++)cout<<a[i]<<" "; //puts(""); for(int i=1; i<=len; i++) { if(((a[i]==1 && b[i]==0)||(a[i]==0 && b[i]==1))) return false; } return true; } int main() { while(~scanf("%d %d",&n,&m)) { F.init(); int cnt; for(int i=1; i<=m; i++) { scanf("%d",&val[i]); for(int j=1; j<=n; j++) { scanf("%d",&str[i][0][j]); } for(int j=1; j<=n; j++) { scanf("%d",&str[i][1][j]); } } // 建边 for(int i=1; i<=m; i++) { if(check1(str[i][0],n)) { F.add(0,i,inf); } if(check2(str[i][1],n)) { F.add(i+m,2*m+1,inf); } F.add(i,i+m,val[i]); for(int j=1; j<=m; j++) { if(i==j) continue; if(cmp(str[i][1],str[j][0],n)) { F.add(i+m,j,inf); } } } cout<<F.solve(0,2*m+1,2*m+2); vector<Edge> ans; F.slove(ans); cout<<" "<<ans.size()<<endl; for(int i=0;i<ans.size();i++){ printf("%d %d %d\n",ans[i].u,ans[i].v,ans[i].w); } } return 0; }