码迷,mamicode.com
首页 > 其他好文 > 详细

「POJ3436」ACM Computer Factory题解

时间:2021-02-22 12:09:10      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:dig   fine   clu   sig   控制流   ||   网络流   dfs   printf   

题意:

有很多台机器,可以把物件从一种状态改装成另一种状态,初始全为\(0\),最终状态全为\(1\),让你可以拼凑机器,请问最大总性能为多少,且要求输出方案。

题解:

这道题是真的水啊,我不想写太多,加一点吧。我们发现,把一个机器当作点来看的话一个机器的加工数即为点权。而点权在网络流的题目里是\(SB\),于是考虑转化为边权。而且我们要控制流量,于是考虑进行拆点。

把点拆开后,因为初始是全为\(0\)的,所以将所有初始状态为\(0\)的机器的入点与超级源点连边,而所有最终状态为\(1\)的机器的出点与超级汇点连边。然后为了形成一条工业线,就去寻找如果有两个机器\(A,B\),其中\(A\)的最终状态就是\(B\)的初始状态,那么\(A\)的出点就会向\(B\)的入点连边。也就是他们可以形成匹配,因为这里你是要跑出一条路径来。

最后跑一遍\(Dinic\),即可求得第一个答案。

那么如何去输出方案呢?另外再开一个数组记录最开始的流量,最后去一一比较,如果存在最终流量与最开始的流量不一样,那么这条边就被用了,然后输出对应的两个点即可。而这边还要你输出匹配的机器方案有几行,那就跑两次就好了。

建模:

\([1]S\)向每个初始全为\(0\)的机器连一条流量为\(INF\)的边,因为你一台机器是可以和多台匹配的,而能不能匹配和可不可以匹配取决于你们之间的关系与剩余流量

\([2]T\)向每个末尾全为\(1\)的机器连一条权值也为\(INF\)的边,因为你一末尾也可以与多台匹配

\([3]\)寻找两个可以匹配的边,这之间同样连流量为\(INF\)的边

\([4]\)每个点的入点向出点连流量为性能效率的边

\(code\):

#include<bits/stdc++.h>
#define int long long
using namespace std;
template<typename T> inline void read(T &x){
    T f=1;x=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘) f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x*=f;
}
const int N = 205,M = 2e4,INF=2e9;
int p,n,nex[M],first[M],v[M],flow[M],num=1,ans=0;
int ss[N][N],tt[N][N],f[N];
int s,t,nxt[N],fro[N],ft[N];
void add(int from,int to,int val){
	nex[++num]=first[from];
	first[from]=num;
	v[num]=to;
	ft[num]=val;
	flow[num]=val;
	fro[num]=from;
}
int dep[N],q[N],no[N];
bool bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	q[1]=s;
	dep[s]=1;
	no[s]=first[s];
	int head=0,tail=1;
	while(head!=tail){
		int u=q[++head];
		for(int i=first[u];i;i=nex[i]){
			int to=v[i];
			if(flow[i] && !dep[to]){
				no[to]=first[to];
				dep[to] = dep[u] + 1;
				q[++tail] = to;
			}
		}
	}
	return dep[t]!=0;
}
int aim;
int dfs(int now,int fl){
	if(now==aim) return fl;
	int f=0;
	for(int i=no[now];i&&fl;i=nex[i]){
		no[now]=i;
		int to=v[i];
		if(flow[i] && dep[to] == dep[now]+1){
	//		from[to]=now;
	//		nxt[now]=to;
			int x=dfs(to,min(fl,flow[i]));
			flow[i]-=x;
			flow[i^1]+=x;
			fl-=x;
			f+=x; 
			if(!fl) break;
		}
	}
	if(!f) dep[now]=-2;
	return f;
}
void mxflow(int s,int t){
	aim=t;
	while(bfs(s,t)){
		ans+=dfs(s,1<<30);
	}
	return;
}
int vis[N];
signed main(){
   read(p),read(n);
    //一个机器有p个零件
    //有n个机器
    s=0;
    t=2*n+1;
    for(int i=1;i<=n;i++){
        read(f[i]);
        for(int j=1;j<=p;j++) read(ss[i][j]);
        for(int j=1;j<=p;j++) read(tt[i][j]);
        
		add(i,i+n,f[i]);
		add(i+n,i,0);
    }
    for(int i=1;i<=n;i++){
    	int flag=0;
    	for(int j=1;j<=p;j++){
    		if(ss[i][j]==1){
    			flag=1;
    			break;
			}
		}
		if(!flag){
			add(s,i,INF);
			add(i,s,0);
		}
		flag=0;
		for(int j=1;j<=p;j++){
    		if(tt[i][j]==0||tt[i][j]==2){
    			flag=1;
    			break;
			}
		}
		if(!flag){
			add(i+n,t,INF);
			add(t,i+n,0);
		}
	}
	
    for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			if(i==j) continue;
			int flag=0;
			for(int k=1;k<=p;k++) {
				if(ss[j][k]==2||tt[i][k]==ss[j][k]) continue;
				flag=1;
				break;
			}
			if(!flag){
				add(i+n,j,INF);
				add(j,i+n,0);
			} 
		}
	}
	mxflow(s,t);
	printf("%lld ",ans);
	int sum=0,cnt=0;	
    int tot=0;
    for(int i=n+1;i<t;i++){
        for(int j=first[i];j;j=nex[j]){
        	if(v[j]>0&&v[j]<=n&&ft[j]>flow[j]){
        	//	printf("%lld %lld %lld\n",i-n,v[j],ft[j]-flow[j]);
        		++cnt;
			} 
        }
	}
    printf("%lld\n",cnt);
    for(int i=n+1;i<t;i++){
        for(int j=first[i];j;j=nex[j]){
        	if(v[j]>0&&v[j]<=n&&ft[j]>flow[j]){
        		printf("%lld %lld %lld\n",i-n,v[j],ft[j]-flow[j]);
			} 
        }
	}
    return 0;
}

「POJ3436」ACM Computer Factory题解

标签:dig   fine   clu   sig   控制流   ||   网络流   dfs   printf   

原文地址:https://www.cnblogs.com/defination/p/14423539.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!