题目大意:
3 4 15 0 0 0 0 1 0 10 0 0 0 0 1 1 30 0 1 2 1 1 1 3 0 2 1 1 1 1组成acm电脑有3个零件,4种机器;
1号机器能产生15次,需要的3个零件:完全不需要(0:不需要,1:一定要,2:可要可不要);产出材料:产出一个单位的2号零件(1:生产该材料,0:不能生产该材料);
2号机器能生产10次,不需要零件,产出一个2,一个3号零件。
3号机器能生产30次,需要2号零件,3号零件可有可无,生产出1,2,3材料各一个。
4号机器.....
题目意思太晦涩了;或许是我英语不好的原因吧。
当某机器的产出与机器的需求能完全匹配上的话,则两台机器可以组成流水线。现在要求的就是:组成流水线产出的机器最大数。
so:
构图基本上就是这样:
直接求最大流,还是很简单的;
但是接下来的问题就是:
去找流边呢??
开始我的想法是:我做完了最大流之后,会有一些反边,也就是流过的边。这样做一次EK用bfs每次去找一条反向到汇点的路径,把这条路径存好就是了。
但是呢... 这样会存在问题:
因为我们一般写网络流已经不再把容量和流量概念放进代码里了,单单保存容量,每次对容量进行操作就可以了。但是这次单单进行简化的可不行了。
如果当前边有流量流过的话flow值一定是非零的。这就是一条可行路径。也就是流水线中间的一环。
所以,对网络流进行操作时,就必须还原到原始的状态,也就是要保存容量与流量。容量对流量进行限制,流量反应流的情况。
这样流完最大流之后,通过边的流量就可以获知机器的排布情况了。
当然可以通过cap与flow值进行bfs,但我们也可以简化思路,直接将有流量有容量的边输出即可。
另外提醒一点:2,也就是可要可不要零件,不能把它当成不要,看上去这种贪心思想是对的。实际上将2变成0,会引起机器之间的不匹配。导致原本可流的边不能流。
CODE:
#include<iostream>
#include<cstdio>
#include<string>
#define INF 0x00FFFFFF
#define MN 111
#define CC(what) memset( what,0,sizeof(what) )
template<class T> void inline checkmin( T &a,T b ){ if( a>b||a==-1 ) a=b; }
using namespace std;int maze[MN][MN],flow[MN][MN],pre[MN],cur[MN],dis[MN],gap[MN];
int P,N,s,t,NE;
struct node{int u,v,a;
}E[MN*MN];void setG()
{int rec[MN][MN];CC(maze);CC(rec);CC(flow);s=0;t=2*N+2;int i,j,k;for( i=1;i<=N;i++ ){scanf("%d",&maze[i<<1][i<<1|1]);for( int j=1;j<=2*P;j++ )scanf("%d",&rec[i][j]);}for( i=1;i<=N;i++ ){for( j=1;j<=N;j++ ){if( i==j ) continue;bool can=true;for( int k=1;k<=P;k++ )if( rec[i][k+P]!=rec[j][k]&&rec[j][k]!=2 ){can=false;break;}if(can)maze[i<<1|1][j<<1]=INF;}int cnt=0;for( k=1;k<=P;k++ )cnt+=(rec[i][k]&1);if(cnt==0) maze[s][i<<1]=INF;cnt=0;for( k=P+1;k<=2*P;k++ )cnt+=rec[i][k];if(cnt==P) maze[i<<1|1][t]=INF;}
}
/*
int sap()
{CC(pre),CC(cur),CC(gap),CC(dis);int u=cur[s]=s,maxflow=0,aug=-1;gap[0]=t+1;while( dis[s]<=t ){
loop:for( int v=cur[u];v<=t;v++ )if( maze[u][v]-flow[u][v]&&dis[u]==dis[v]+1 ){cur[u]=v;checkmin(aug,maze[u][v]-flow[u][v]);pre[v]=u;u=v;if( v==t ){maxflow+=aug;for( u=pre[u];v!=s;v=u,u=pre[u] )flow[u][v]+=aug,flow[v][u]-=aug;aug=-1;}goto loop;}int mind=t+1;for( int v=0;v<=t;v++ )if( maze[u][v]&&mind>dis[v] ){cur[u]=v;mind=dis[v];}if( --gap[dis[u]]==0 ) break;gap[dis[u]=mind+1]++;u=pre[u];}return maxflow;
}
*/
int vis[MN],que[MN],a[MN];
bool bfs()
{CC(vis);CC(que);int head=0,foot=0;que[foot++]=s;a[s]=INF;vis[s]=true;while( head<foot ){int u=que[head++];for( int i=s;i<=t;i++ )if( !vis[i]&&maze[u][i]-flow[u][i] ){pre[i]=u;vis[i]=true;que[foot++]=i;a[i]=min(a[u],maze[u][i]-flow[u][i]);if( i==t ) return true;}}return false;
}int work()
{int maxflow=0;while( bfs() ){int m=t;maxflow+=a[t];while( m!=s ){flow[pre[m]][m]+=a[t];flow[m][pre[m]]-=a[t];m=pre[m];}}return maxflow;
}
int main()
{while( scanf("%d%d",&P,&N)!=EOF ){setG();printf( "%d ",work() );int ans[MN*MN][3];int pathnum=0;for( int i=1;i<t;i++ )for( int j=1;j<t;j++ ){if( maze[i][j]>0&&flow[i][j]>0&&i/2!=j/2 ){ans[pathnum][0]=i/2;ans[pathnum][1]=j/2;ans[pathnum++][2]=flow[i][j];}}printf( "%d\n",pathnum );for( int i=0;i<pathnum;i++ )printf( "%d %d %d\n",ans[i][0],ans[i][1],ans[i][2] );}return 0;
}