链接:http://poj.org/problem?id=3436
题意:有N台机器,输入输出都有P种配件。
输入有0,1,2,三种状态,分别代表不需要该配件,需要该配件,该配件可有可无。
输出有0,1,两种状态,分别代表该配件没有产出,该配件产出。
只有当满足某台机器的输出满足某个机器的输入时,两台机器才是完成协作。
如果一台机器的所有输出为1,且满足了它的输入,则表示产出了一台电脑。
参考网上思路。
拆点法。
把每个机器拆成两个点(输入点和输出点),i和i+n
建图:
如果机器的输入中没有1存在,则与源点连边,边权为INF
如果机器的输出中只有1存在,则与汇点连边,边权为INF
机器自身输入点和输出点连边,权值为这台机器的performance,即Qi
如果一台机器的输出满足另一台机器的输入,则两天机器连边,边权为INF
构图老是参考网上的,自己也不想想,怎么办啊~~~~这样下去怎么会有长进啊啊啊啊啊啊啊啊
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 110
#define MAXP 15
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int map[MAXN][MAXN],mach[MAXN]; //map构建图,mach存储Qi
int in[MAXN][MAXP],out[MAXN][MAXP];//存储每个机器的输入输出的配件要求
int ans;
int dist[MAXN];
int resa[2*MAXN],resb[2*MAXN],resp[2*MAXN];
int st_in(int in[][MAXP],int p,int i)
{
int j;
for(j=0;j<p;j++)
if(in[i][j]==1)
return 0;
return 1;
}
int ed_out(int out[][MAXP],int p,int i)
{
int j;
for(j=0;j<p;j++)
if(out[i][j]!=1)
return 0;
return 1;
}
int out_in(int out[][MAXP],int in[][MAXP],int i,int j,int p)
{
int m;
for(m=0;m<p;m++)
if((out[i][m]+in[j][m])==1)
return 0;
return 1;
}
int BFS(int st,int ed)
{
int k,i;
memset(dist,-1,sizeof(dist));
dist[st]=0;
queue<int> q;
q.push(st);
while(!q.empty())
{
k=q.front();
q.pop();
for(i=0;i<=ed;i++)
{
if(map[k][i]>0&&dist[i]<0)
{
dist[i]=dist[k]+1;
q.push(i);
}
}
}
if(dist[ed]>0)
return 1;
return 0;
}
int DFS(int x,int ed,int low)
{
int i,a;
if(x==ed)
return low;
for(i=0;i<=ed;i++)
{
if(map[x][i]>0&&dist[i]==dist[x]+1&&(a=DFS(i,ed,MIN(low,map[x][i]))))
{
map[x][i]-=a;
map[i][x]+=a;
return a;
}
}
return 0;
}
void Dinic(int st,int ed)
{
int res;
while(BFS(st,ed))
{
while((res=DFS(st,ed,INF)))
{
ans+=res;
}
}
return;
}
int main()
{
int p,n,i,j;
int st,ed,cnt;
while(scanf("%d%d",&p,&n)!=EOF)
{
memset(mach,0,sizeof(mach));
memset(map,0,sizeof(map));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
st=0; //超级源点
ed=2*n+1; //超级汇点
for(i=1;i<=n;i++)
{
scanf("%d",&mach[i]);
map[i][i+n]=mach[i]; //拆点,每个机器拆成输入点i和输出点i+n
//输入点和输出点连边,权值为这台机器的performance,即Qi
for(j=0;j<p;j++)
scanf("%d",&in[i][j]);
for(j=0;j<p;j++)
scanf("%d",&out[i][j]);
if(st_in(in,p,i)) //如果机器的输入中没有1存在,则与源点连边,边权为INF
map[st][i]=INF;
if(ed_out(out,p,i)) //如果机器的输出中只有1存在,则与汇点连边,边权为INF
map[i+n][ed]=INF;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(out_in(out,in,i,j,p)) //如果一台机器的输出满足另一台机器的输入,则两天机器连边,边权为INF
map[i+n][j]=INF;
ans=0;
cnt=0;
Dinic(st,ed); //用Dinic求最大流
printf("%d ",ans);
for(i=1;i<=n;i++) //在除了源点和汇点所在的边内找connection
for(j=1;j<=n;j++)
{
if(i!=j&&map[j][i+n]>0)//大于零的反向边就是我们要找的路径
{
resa[cnt]=i;
resb[cnt]=j;
resp[cnt]=map[j][i+n];
cnt++;
}
}
printf("%d\n",cnt);
for(i=0;i<cnt;i++)
printf("%d %d %d\n",resa[i],resb[i],resp[i]);
}
return 0;
}