题意(参考北京大学郭炜老师课件):每个工厂有三个动作:1)接收原材料;2)生产 ;3)将其产出的半成品给其他机器,或产出成品。这三个过程都对应不同的流量。对第一组输入数据的分析:
输入:
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
输出:
25 2
1 3 15
2 3 10
输入解释:电脑由3个部件组成,共有4台机器,1号机器产量15, 能给空电脑加上2号部件;2号机器能给空电脑加上2号部件和3号部件,;3号机器能把具有1个2号部件和3号部件有无均可的电脑变成成品;4号机器能把具有1个3号部件和2号部件有无均可的电脑变成成品.
输出:单位时间最大产量25,有两台机器有协作关系:
1号机器单位时间内要将15个电脑给3号机器加工
2号机器单位时间内要将10个电脑给3号机器加工
注意:输出可能由多种可能,输出其中任意一种即可,而且协作关系的顺序随意。所以对于上述输入,如下输出也是正确的:
25 3
2 4 3
2 3 7
1 3 15
思路:
1) 添加一个原点S,S提供最初的原料 00000...
2) 添加一个汇点T, T接受最终的产品 11111....
3) 将每个机器拆成两个点: 编号为i的接收节点,和编号为i+n的产出节点(n是机器数目),前者用于接收原料,后者用于提供加工后的半成品或成品。这两个点之间要连一条边,容量为单位时间产量Qi
4) S 连边到所有接收 "0000..." 或 "若干个0及若干个2" 的机器,容量为无穷大
5) 产出节点连边到能接受其产品的接收节点,容量无穷大
6) 能产出成品的节点,连边到T,容量无穷大。
7) 求S到T的最大流
#include <stdio.h>
#include <string.h>
#define min(a,b) a<b?a:b
#define N 105
#define INF 0x3fffffff
struct edge{
int y,c,next;
}e[N*N];
int p,n,top;
int in[N/2][11],out[N/2][11],w[N/2];
int index[N],first[N],pre[N],a[N],q[200000];
int iszero(int x[11]){//可以接受空电脑,也就是连接到超级源点
int i,temp=0;
for(i = 1;i<=p;i++)
if(x[i] == 1)
return 0;
return 1;
}
int isone(int x[11]){//所有的零件装配齐全,连接到超级汇点
int i,temp=0;
for(i = 1;i<=p;i++)
temp += x[i];
if(temp==p)
return 1;
return 0;
}
void add(int x,int y,int c){
e[top].y = y;
e[top].c = c;
e[top].next = first[x];
first[x] = top++;
e[top].y = x;
e[top].c = 0;
e[top].next = first[y];
first[y] = top++;
}
int test(int x[11],int y[11]){//测试y能否接收x的输出
int i;
for(i = 1;i<=p;i++)
if(x[i]+y[i] == 1)
return 0;
return 1;
}
void maxflow(int s,int t){
int i,j,res=0,sum=0,now,front,rear;
front = rear = -1;
while(1){
memset(a,0,sizeof(a));
memset(pre,0,sizeof(pre));
q[++rear] = s;
a[s] = INF;
while(front < rear){
now = q[++front];
for(i = first[now];i!=-1;i=e[i].next)
if(!a[e[i].y] && e[i].c>0){
q[++rear] = e[i].y;
a[e[i].y] = min(a[now],e[i].c);
pre[e[i].y] = now;
index[e[i].y] = i;
}
}
if(!a[t])
break;
res += a[t];
for(i = t;i!=0;i=pre[i]){
e[index[i]].c -= a[t];
e[index[i]^1].c += a[t];
}
}
for(i = t-2;i>0;i-=2)//计算有协作关系的数量
for(j = first[i];j!=-1;j=e[j].next)
if(e[j].c>0 && e[j].y!=0 && e[j].y!=i+1)//奇数节点的反向边有流量且不是留回源点的就是我们要找的
sum++;
printf("%d %d\n",res,sum);
}
void print(int t){
int i,j;
for(i = t-2;i>0;i-=2)
for(j = first[i];j!=-1;j=e[j].next)
if(e[j].c>0 && e[j].y!=0 && e[j].y!=i+1)
printf("%d %d %d\n",e[j].y/2,(i+1)/2,e[j].c);//奇数节点的反向边有流量且不是留回源点的就是我们要找的
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d %d",&p,&n)!=EOF){
int i,j;
top = 0;
memset(first,-1,sizeof(first));
for(i = 1;i<=n;i++){
scanf("%d",&w[i]);
for(j = 1;j<=p;j++)
scanf("%d",&in[i][j]);
for(j = 1;j<=p;j++)
scanf("%d",&out[i][j]);
if(iszero(in[i]))
add(0,2*i-1,INF);
if(isone(out[i]))
add(2*i,2*n+1,INF);
add(2*i-1,2*i,w[i]);
}
for(i = 1;i<=n;i++)
for(j = 1;j<=n;j++)
if(test(out[i],in[j]))
add(2*i,2*j-1,INF);
maxflow(0,2*n+1);
print(2*n+1);
}
return 0;
}
本文介绍了一个具体的最大流问题实例,通过构建计算机组装生产线的模型来解决。文章详细展示了如何使用图论中的最大流算法确定生产线中各环节的最佳协作关系及单位时间内的最大产量。
467

被折叠的 条评论
为什么被折叠?



