题意:
每一个机器有一个物品最大工作数量,还有一个对什么物品进行加工,加工后的物品是什么样。给你无限多个初始都是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 ",ans); 138 for(int i=0;i<ans;++i) 139 { 140 printf("%d %d %d ",que[i].u,que[i].v,que[i].w); 141 } 142 return 0; 143 }