题意:
每一个机器有一个物品最大工作数量,还有一个对什么物品进行加工,加工后的物品是什么样。给你无限多个初始都是000....的机器,你需要找出来经过这些机器操作后最多有多少成功的机器(111.....)
题解:
st是网络流起始点,en是终止点
首先肯定是要拆点的,因为题目上给出的是每一个机器的最大加工数量。这是对于机器本身,所以拆点之后i->start和i->last这条边的容量就是机器的最大加工数量
这个题的话建图很清晰,只要它要加工的原始物品是000...类型的,它就可以和st建一条边,容量无限大。如果加工后的物品是111...这种类型的,那么就可以让这个i->last和en建一条边,容量都是无限大
之后的话如果某个机器加工后的产品可以作为某个机器的原料,那就让他们之间连一条容量无限大的边。这里要注意,当某个机器接受的原料某个部件为2,那这个位置有没有部件都可以连边
例:1机器原料为1 2 1,那么1 0 1和1 1 1的产品他都可以接收
因为题目要求最后要输出那两个机器之间有流量,所以只要跑完最大流之后一个一个点的去检查。发现这个点和其他点之间有流量,那就出输出它(具体看代码)
代码:

1 #include <cstdio>
2 #include <algorithm>
3 #include <iostream>
4 #include <cstring>
5 #include <vector>
6 #include <queue>
7 #define INF 99999999
8 using namespace std;
9 const int N = 150;
10 int p,n,cnt;
11 int capacity[N],m[N][N],head[N],cur[N],d[N];
12
13 struct edge
14 {
15 int u,v,c,flow,next;
16 } e[N*N];
17 struct shudui
18 {
19 int u,v,w;
20 }que[N*N];
21 void adde(int u,int v,int w,int f)
22 {
23 e[cnt].v=v;
24 e[cnt].u=u;
25 e[cnt].c=w;
26 e[cnt].flow=f;
27 e[cnt].next=head[u];
28 head[u]=cnt++;
29 }
30 bool bfs(int s,int t)
31 {
32 for(int i=0; i<=2*n+2; i++) d[i]=0;
33 d[s]=1;
34 queue <int > q;
35 q.push(s);
36 while(!q.empty())
37 {
38 int u=q.front();
39 q.pop();
40 for(int i=head[u]; i!=-1; i=e[i].next)
41 {
42 int v=e[i].v;
43 if(!d[v] && e[i].c>e[i].flow)
44 {
45 d[v]=d[u]+1;
46 q.push(v);
47 }
48 }
49 }
50 return d[t]!=0;
51 }
52 int dfs(int s,int a)
53 {
54 if(s==2*n+1 || a==0) return a;
55 int flow = 0;
56 for(int &i=cur[s]; i!=-1; i=e[i].next)
57 {
58 int v=e[i].v,f;
59 if(d[v]!=d[s]+1) continue ;
60 f=dfs(v,min(a,e[i].c-e[i].flow));
61 if(f)
62 {
63 e[i].flow+=f;
64 e[i^1].flow-=f;
65 a-=f;
66 flow+=f;
67 if(a==0) break;
68 }
69 }
70 if(!flow) d[s]=-1;
71 return flow;
72 }
73 int main()
74 {
75 scanf("%d%d",&p,&n);
76 memset(head,-1,sizeof(head));
77 for(int i=1; i<=n; i++)
78 {
79 scanf("%d",&capacity[i]);
80 for(int j=1; j<=2*p; j++) scanf("%d",&m[i][j]);
81 }
82
83 for(int i=1; i<=n; i++)
84 {
85 adde(i,i+n,capacity[i],0);
86 adde(i+n,i,0,0);
87 int flag1=1,flag2=1;
88 for(int j=1; j<=p; j++)
89 {
90 if(m[i][j]==1) flag1=0;
91 if(m[i][j+p]!=1) flag2=0;
92 }
93 if(flag1) adde(0,i,INF,0),adde(i,0,0,0);
94 if(flag2) adde(i+n,2*n+1,INF,0),adde(2*n+1,i+n,0,0);
95 }
96 for(int i=1; i<=n; i++)
97 {
98 for(int j=1; j<=n; j++) //这里j的初始值不能是i+1,卧槽!!
99 {
100 if(i==j) continue ;
101 bool ok = true ;
102 for(int k=p+1; k<=p*2; k++)
103 {
104 int now = k-p;
105 if(m[j][now]==2) continue ;
106 if(m[i][k]!=m[j][now]) ok=false;
107 }
108 if(ok)
109 {
110 adde(i+n,j,INF,0);
111 adde(j,i+n,0,0);
112 }
113 }
114 }
115 int max_flow = 0;
116 while(bfs(0,2*n+1))
117 {
118 for(int i=0; i<=2*n+1; i++) cur[i]=head[i];
119 max_flow+=dfs(0,INF);
120 }
121 printf("%d ",max_flow);
122 int ans=0;
123 for(int i=1+n; i<=2*n; i++) //如果两个点之间有合作关系,那么他们的e[j].flow肯定不会为0,就是利用这一点找出来所有有合作关系的
124 { //点。题目没有要求怎么输出,那就随便输出就可以
125 for(int j=head[i]; j!=-1; j=e[j].next)
126 {
127 int v=e[j].v;
128 if(v!=2*n+1 && v!=0 && e[j].flow && v!=i-n)
129 {
130 que[ans].u=i-n;
131 que[ans].v=v;
132 que[ans].w=e[j].flow;
133 ans++;
134 }
135 }
136 }
137 printf("%d\n",ans);
138 for(int i=0;i<ans;++i)
139 {
140 printf("%d %d %d\n",que[i].u,que[i].v,que[i].w);
141 }
142 return 0;
143 }
