POJ 3436 ACM Computer Factory(最大流 残留网络找边)

坑爹啊!!!!!!!

这题弄了我一天啊!到最后在样例都没过的情况下,怀着无语的心情蛮交了一次,竟然过了!这不是坑爹是什么!

不过分析了一下,这样的情况应该也是算对的!因为增广路可能的情况本身就有许多种,所以样例不过的情况也是允许的吧!

这题的意思其实有点乱,不过梳理一下就比较容易理解,首相想到是网络流的题目比较有困难,然后就是题意了。具体是,以“工厂”作为节点,intput 全为2是与源点连通,制造一个0为源点,2*n+1为汇点。。
剩下的把每个机器(节点)分解成两个点(i,i+n),这两个点之间最大流量即为Performance。。
其他可用的边流量都是无穷大,记得1-n的点只能进,n+1-2*n的点只能出。。。
例如:机器i的完成品可用到j上加工  maxflow[i+n][j]=MAXINT。。。祝大家最大流愉快!

附上代码,其实主要是我一直想使用自己的Dinic模板,不想换,所以坑了我一整天。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn=150000;
const int maxm=200000;
const int inf=1<<30;
struct edge
{
	int from,to,val,next;
	int flow;
}map[maxn];
edge lex[500];
int vis[maxn],que[maxn],dist[maxn],len,n;
int vised[maxn];
int pcnt=0;
int T;
void init()
{
	len=0;
	memset(vis,-1,sizeof(vis));
}
void insert (int from,int to,int val)
{
	map[len].from=from;
	map[len].to=to;
	map[len].val=val;
	map[len].flow=val;
	map[len].next=vis[from];
	vis[from]=len++;
	map[len].from=to;
	map[len].to=from;
	map[len].val=0;
	map[len].flow=0;
	map[len].next=vis[to];
	vis[to]=len++;
}
int Dinic(int n,int s,int t)
{
	int ans=0;
	while(true)
	{
		int head,tail,id,i;
		head=tail=0;
		que[tail++]=s;
		memset(dist,-1,sizeof(dist));
		dist[s]=0;
		while(head<tail)
		{
			id=vis[que[head++]];
			while(id!=-1)
			{
				if(map[id].val>0&&dist[map[id].to]==-1)
				{
					dist[map[id].to]=dist[map[id].from]+1;
					que[tail++]=map[id].to;
					if(map[id].to==t)
					{
						head=tail;
						break;
					}
				}
				id=map[id].next;
			}
		}
		if(dist[t]==-1)
			break;
		id=s,tail=0;
		while(true)
		{
			if(id==t)       //找到一条增广路
			{
				int flow=inf,fir;
				for(i=0;i<tail;i++)
					if(map[que[i]].val<flow)
					{
						fir=i;
						flow=map[que[i]].val;
					}
					for(i=0;i<tail;i++)
						map[que[i]].val-=flow,map[que[i]^1].val+=flow;
					ans+=flow;
					tail=fir;
					id=map[que[fir]].from;
			}
			id=vis[id];
			while(id!=-1)
			{
				if(map[id].val>0&&dist[map[id].from]+1==dist[map[id].to])
					break;
				id=map[id].next;
			}
			if(id!=-1)
			{
				que[tail++]=id;
				id=map[id].to;
			}
			else
			{
				if(tail==0)
					break;
				dist[map[que[tail-1]].to]=-1;
				id=map[que[--tail]].from;
			}
		}
	}
	return ans;
}      //以上依然是纯模板
int main()
{
	int p,i,j,k;
	int num[51][101];
	while(scanf("%d%d",&p,&n)!=EOF)
	{
		int flag,flag1;
		init();
		memset(num,0,sizeof(num));
		T=2*n+1;
		for(i=1;i<=n;i++)
			for(j=0;j<=2*p;j++)
				scanf("%d",&num[i][j]);         //建图输入   num[i][0]  都未这个工厂的效率
			for(i=1;i<=n;i++)
			{
				flag=1;
				flag1=1;
				insert(i,i+n,num[i][0]);
				for(j=1;j<=p;j++)
				{
					if(num[i][j]!=0&&num[i][j]!=2)       //判断是否和源点相连
						flag=0;
					if(num[i][j+p]!=1)    //判断是否和汇点相连
						flag1=0;
				}
				if(flag)
					insert(0,i,num[i][0]);    //运用上面的判断是否建立边
				if(flag1)
					insert(n+i,2*n+1,num[i][0]);
				for(j=1;j<=n;j++)
				{
					int kkk=1;
					for(k=1;k<=p;k++)
						if(j!=i)							   
							if(num[i][k+p]!=num[j][k]&&num[j][k]!=2) //判断前一个工厂的结果是否为下一个工厂的前提
							{
								kkk=0;
								break;
							}		
							if(kkk)
							{
								insert(i+n,j,inf);       
							}
				}
			}
			memset(vised,0,sizeof(vised));
			int ans=Dinic(T+1,0,T);
			pcnt=0;
			for(i=n+1;i<=2*n+1;i++)
				for(j=vis[i];j!=-1;j=map[j].next)
					     if(map[j].to>0&&map[j].to<=n&&map[j].val<map[j].flow)    //这个地方坑了我无限久,找残留网络中的点,不为0或者不为inf值就是需要的边
							 pcnt++;
			printf("%d %d\n",ans,pcnt);
			for(i=n+1;i<=2*n+1;i++)
				for(j=vis[i];j!=-1;j=map[j].next)  //再来一次输出就好
				    if(map[j].to>0&&map[j].to<=n&&map[j].val<map[j].flow)
							 cout<<i-n<<" "<<map[j].to<<" "<<map[j].flow-map[j].val<<endl;

			
	}
	return 0;
}
 
依然希望大家自己去考虑考虑,模板什么都坚持使用一种!
posted @ 2011-08-20 17:01  Lxsec  阅读(731)  评论(0编辑  收藏  举报