POJ 3436:拆点最大流

本文介绍了一个使用网络流算法解决电脑组装流水线效率问题的方法。通过将机器加工过程抽象为网络流模型,实现了最大流量计算,进而确定了每小时最多能组装的电脑数量及对应的流水线工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:一个电脑有P个部件组成,刚开始所有电脑都是空壳子,当一个电脑具备了所有的N个部件则认为这个电脑早好了。现在有一些机器专门加工电脑,每个机器可以加工某一些特性状态原型机,比如必须具备1部件,必须没有3部件,2部件有没有都行,然后这些原型机经过这个机器的加工,就会变成一种特定状态,比如具备123部件,没有45部件。每个机器每小时可以加工qi个原型机。

求出每小时最多生产多少个成品机。以及流水线的运作情况。


题解:题意特别绕。。。。但是题解是很显然的网络流。对于每个机器,拆成一个入点和出点,入点->出点链接一个容量qi的边。然后二重枚举机器,如果第i个机器的输出可以做得第j个机器的输入,那么就链接i的出点->j的入点,容量INF。然后再开一个超级源,如果裸机可以作为i点的输入,就链接源->i的入点,容量INF。如果第i个机器产出成品机,那就链接i的出点->汇,容量INF。


这里机器的每小时加工数量在入点-出点的边限制住了。


很裸的网络流。。。和网络流基本的油管运输问题基本一摸一样。

Code:

#include<stdio.h>
#include<cstring> 
#include<queue>
using namespace std;
const int maxn = 55;
const int maxp = 15;
const int INF = 0x3f3f3f3f;
int in[maxn*2][maxp],out[maxn][maxp],q[maxn];
int tot,first[maxn],nxt[maxn*maxn],des[maxn*maxn],flow[maxn*maxn];
int dep[maxn];
int ss,tt;
int p,n;
inline void addEdge(int x,int y,int z){
	tot++;
	des[tot] =y;
	flow[tot] =z;
	nxt[tot] = first[x];
	first[x] = tot;
	
	tot++;
	des[tot] =x;
	flow[tot] =0;
	nxt[tot] = first[y];
	first[y] = tot;
}
void init(){
	ss=1;tt=2*n+2;
	tot =-1;
}
void input(){
//	scanf("%d%d",&p,&n);
	for (int i=2;i<=n+1;i++){
		scanf("%d",q+i);
		for (int j=0;j<p;j++){
			scanf("%d",&in[i][j]);
		}
		for (int j=0;j<p;j++){
			scanf("%d",&out[i][j]);
		}
	}
}
void build (){
	memset(first,-1,sizeof first);
	for (int i=2;i<=n+1;i++){
		addEdge(i,i+n,q[i]);
		bool flag =true;
		for (int j=0;j<p;j++){
			if (in[i][j]==1){
				flag = false;
				break;
			}
		}
		if (flag){
			addEdge(ss,i,INF);
		}
		flag = true;
		for (int j=0;j<p;j++){
			if (out[i][j]!=1){
				flag = false;
				break;
			}
		}
		if (flag){
			addEdge(i+n,tt,INF);
		}
	}
	for (int i=2;i<=1+n;i++){
		for (int j=2;j<=1+n;j++){
			if (i==j)continue;
			bool flag = true;
			for (int k=0;k<p;k++){
				if (out[i][k]==in[j][k]||in[j][k]==2)continue;
				else{
					flag = false;
					break;
				}
			}
			if (flag){
				addEdge(i+n,j,INF);
			}
		}
	}
}
bool bfs(){
//	cout<<"bfs"<<endl;
	queue<int> Q;
	memset(dep,-1,sizeof dep);
	dep[ss]=0;
	Q.push(ss);
	while (!Q.empty()){
		int q = Q.front();Q.pop();
		for (int t = first[q];t!=-1;t=nxt[t]){
			int v = des[t];
			int c = flow[t];
			if (c&&dep[v]==-1){
				dep[v] = dep[q]+1;
				Q.push(v);
			}
		}
	}
	return dep[tt]!=-1;
}
int dfs(int node,int now){
//	cout<<"dfs"<<endl;
	if (node==tt)return now;
	int ret =0;
	for (int  t= first[node];t!=-1&&ret<now;t=nxt[t]){
		int v = des[t];
		int c = flow[t];
		if (dep[v]==dep[node]+1&&c){
			int x = min(c,now-ret);
			x = dfs(v,x);
			flow[t]-=x;
			flow[t^1]+=x;
			ret+=x;
		}
	}
	if (!ret)dep[node] =-1;
	return ret;
}
int max_flow(){
	int tot =0;
	while (bfs()){
		int del;
		while (del=dfs(ss,INF)){
			tot+=del;
		}
	}
	return tot;
}
void solve(){
	int ans =max_flow();
	vector<pair<pair<int,int>,int> >list;
	for (int i=2;i<=n+1;i++){
		for (int t = first[i];t!=-1;t = nxt[t]){
			int v = des[t];
			int c = flow[t];
			if (c&&v>n+1&&v!=2*n+2&&v!=i+n){
//				printf("%d %d %d\n",v-n-1,i-1,c);
				list.push_back(make_pair(make_pair(v-n-1,i-1),c));
			}
		}
	}
	printf("%d %d\n",ans,list.size());
	for (int i=0;i<list.size();i++){
		printf("%d %d %d\n",list[i].first.first,list[i].first.second,list[i].second);
	}
}
int main(){
	while (scanf("%d%d",&p,&n)!=EOF){
		init();
		input();
		build();
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值