题目大意:
有n台机器,P种零件,每种零件有 0 和 1 两种状态,接下来有n行,每行第一个表示机器的效率,其余表示每台机器对于P零件的需求 0 表示不需要,1表示需要,2表示无所谓。现在需要找一些生产线可以把全部的零件制造出来(使零件的状态为1,起始状态为0)。求这些的生产线的最大生产量,并记录有几条生产线和每条生产线的路径
作为一道比较简单的网络流的题目!
这道题的主要问题为:
1.如何建图?如何判断机器可以连接?
2.如何寻找生产线?
3.如何记录生产线的条数和生产线的路径?
思路:
1.为了建图,可以开一个数组,两两判断,如果这两条边可以连接,那么在数组中记录一下两点的最小产量,简单来说就是流量
2.寻找生产线就用EK算法,相对来说比较简单,注意!这道题没有源点,或者说每个点都可能成为源点,为了方便,自己造一个源点和终点,源点初始化为0,终点初始化为1
3.记录生产线
首先!如果加入新的路线 1->1 其实是不影响生产线的,但是如果把这条生产线存到数组中,在EK算法中使用的话,那么可以记录那些点流入过流量,或者流出过流量。(注意用额外的数组,不能跟原来的数组用一个数组)
这里的flow数组糅合了很多作用,所以开的比较大,是原来的4倍,这些部分都有用途
#include<stdio.h>
#include<queue>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;
const int inf=0x3f3f3f3f;
const int MAXN=60;
const int MAXP=12;
int in[MAXN][2*MAXP],flow[2*MAXN][2*MAXN];
int n,p;
int EK(int s,int t) //广搜搜索增广路
{
queue<int> q;
int p[MAXN*2],a[MAXN*2];
int f=0;
while(1)
{
memset(a,0,sizeof(a));
a[s]=inf;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int v=0; v<=2*n+1; ++v)
if(!a[v]&&flow[u][v])//如果这个点与u点相连并且未被选中过
{
p[v]=u,q.push(v);//将V点加入队列中,p是用来记录路径
a[v]=min(a[u],flow[u][v]);//a是用来寻找增广路的
if(v==t) break;
}
}
if(a[t]==0) break;//找不到增广路后跳出循环
for(int u=t; u!=s; u=p[u])//增广路后,将所有的路减去相应流量!然后反向边加上流量
{
flow[p[u]][u]-=a[t];
flow[u][p[u]]+=a[t];
}
f+=a[t];
}
return f;
}
int main()
{
while(scanf("%d%d",&p,&n)==2)
{
for(int i=1; i<=n; ++i)
for(int j=0; j<2*p+1; ++j)//将零件状态存入
scanf("%d",&in[i][j]);
for(int i=1; i<=2*p; ++i)//没有源点和终点,自己设立一个
{
in[0][i]=0;//第一行零件设为0,为源点
in[n+1][i]=1;//n+1行零件全设为1,为终点
}
memset(flow,0,sizeof(flow));
for(int i=1; i<=n; ++i)//每个点都连接到自己,然后流量是自己
flow[i][i+n]=in[i][0];
for(int i=0; i<=n+1; ++i)
for(int j=0; j<=n+1; ++j)
{
if(i==j) continue;
bool flag=true;
for(int k=1; k<=p; ++k)
{
if(in[j][k]!=2&&in[i][k+p]!=in[j][k])
{
flag=false;
break;
}
}
if(flag&&i==0) flow[i][j]=in[j][i];//和源点和终点相连的点特殊处理一下
else if(flag&&j==n+1) flow[i+n][2*n+1]=in[i][0];
else if(flag) flow[i+n][j]=min(in[i][0],in[j][0]);//将所有可以连接的机器记录一下,并记录这条边的最大流量
}
for(int i=0; i<=2*n+1; i++)
{
for(int j=0; j<=2*n+1; j++)
{
printf("%2d ",flow[i][j]);
}
printf("\n");
}
printf("\n\n");
printf("%d ",EK(0,2*n+1));
printf("\n\n\n");
for(int i=0; i<=2*n+1; i++)
{
for(int j=0; j<=2*n+1; j++)
{
printf("%2d ",flow[i][j]);
}
printf("\n");
}
int cnt=0;
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
if(flow[j][i+n]>0&&i!=j)
{
printf("%d %d*-*\n",j,i+n);
++cnt;
}
printf("%d\n",cnt);
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
if(flow[j][i+n]>0&&i!=j)
printf("%d %d %d\n",i,j,flow[j][i+n]);
}
return 0;
}