POJ 1149 PIGS

http://poj.org/problem?id=1149

網絡流,主要是建圖的問題

題意:

有 M 個豬圈(M ≤ 1000),每個豬圈裏初始時有若干頭豬。

一開始所有豬圈都是關閉的。

依次來了 N 個顧客(N ≤ 100),每個顧客分別會打開指定的幾個豬圈,從中買若干頭豬。

每個顧客分別都有他能夠買的數量的上限。

每個顧客走後,他打開的那些豬圈中的豬,都可以被任意地調換到其它開着的豬圈裏,然後所有豬圈重新關上。

問總共最多能賣出多少頭豬。

注意: 顧客是一個接一個的來買豬,而不是同時來

 

建圖:

每個顧客分別用一個節點來表示。

對於每個豬圈的第一個顧客,從源點向他連一條邊,容量就是該豬圈裏的豬的初始數量。如果從源點到一名顧客有多條邊,則可以把它們合併成一條,容量相加。

若第i個人與他後面的第j個人有同一個豬圈的鑰匙,則從i引邊到j,容量爲無窮大

從各個顧客到匯點各有一條邊,容量是各個顧客能買的數量上限

#include<stdio.h>
#include<string.h>
#include<vector>
#define M 120
#define INF 0xfffffff
using namespace std;

int n,m;
int g[M][M];
int d[M];
int stack[M];
int que[M*M];
int num[1001];//各個豬圈豬的數量 
vector<int> G[M];//圖的鄰接表 
vector<int> cus[1001];//cus[i]保存的是能打開i號豬圈的所有顧客 

bool BFS(int s,int t)
{
	int l=0,r=0;
	int i,p;
	memset(d,-1,sizeof(d));
	d[s]=0;
	que[r++]=s;
	while(l<r)
	{
		p=que[l++];
		for(i=0;i<G[p].size();i++)
		{
			int u=G[p][i];
			if( g[p][u]>0 && d[u]==-1)
			{
				d[u]=d[p]+1;
				if(u==t) 
					return true;
				que[r++]=u;
			}
		}
	}
	return false;
}

int Dinic(int s,int t)
{
	int i,p;
	int mn;
	int nMinc;
	int maxflow=0;
	bool v[M];
	
	while(BFS(s,t))
	{
		int top=0,base=0;
		stack[top++]=s;
		memset(v,false,sizeof(v));
		v[s]=true;
		while(top>base)
		{
			p=stack[top-1];
			if(p==t)
			{
				mn=INF;
				for(i=1;i<top;i++)
				{
					int u=stack[i-1];
					int v=stack[i];
					if(g[u][v]<mn)
					{
						mn=g[u][v];
						nMinc=u;
					}
				}
				maxflow+=mn;
				for(i=1;i<top;i++)
				{
					int u=stack[i-1];
					int v=stack[i];
					g[u][v]-=mn;
					g[v][u]+=mn;
				}
				while(top>base && stack[top-1]!=nMinc)
					top--;
			}
			else 
			{
				for(i=0;i<G[p].size();i++)
				{
					int u=G[p][i];
					if( !v[u] && g[p][u]>0 && d[u]==d[p]+1)
					{
						v[u]=true;
						stack[top++]=u;
						break;
					}
				}
				if(i==G[p].size())
					top--;
			}
		}
	}
	return maxflow;
}

int main()
{
	int i,j;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(g,0,sizeof(g));
		memset(num,0,sizeof(num));
		memset(cus,0,sizeof(cus));
		memset(G,0,sizeof(G));
		for(i=1;i<=m;i++)
			scanf("%d",&num[i]);
		for(i=1;i<=n;i++)
		{
			int k,p;
			scanf("%d",&k);
			while(k--)
			{
				int a;
				scanf("%d",&a);
				if(cus[a].size()==0)//如果i是第一個能打開a豬圈的顧客
				{	
					g[0][i]+=num[a];
					cus[a].push_back(i);
					G[0].push_back(i);
				}
				else 
				{
					for(j=0;j<cus[a].size();j++)//每個能打開a豬圈的顧客都向i連一條無窮的的邊 
					{
						int u=cus[a][j];
						g[u][i]=INF;
						G[u].push_back(i);
						G[i].push_back(u);
					}
				}
			}
			scanf("%d",&p);
			g[i][n+1]=p;//每個顧客與匯連一條邊 
			G[i].push_back(n+1);
		}
		printf("%d\n",Dinic(0,n+1));
	}
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章