题目大意:
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;
}