poj1149 PIGS

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

构图果然很关键。这是参考他人的构图。

思路:对于某个猪圈i,设拥有这个猪圈钥匙的人序列为Pi1,Pi2...Pij,则从源向Pi1连一条容量为猪圈i初始猪数的边(记得容量为累加),在相邻两个点之间连无穷大边,每个点到汇点连一条容量为需求量的边.然后求最大流即可。

构图好后,用最大流的算法做就可以了。

不过这个题,我用邻接矩阵的SAP做,交了N次WA。。。。不知道还有什么地方有错了啊。。。

然后无奈用Dinic做了,1A。

 

关键是我不知道我的SAP有没有错啊。以后还得靠这模板混日子呢。。。。

#include<cstdio>
#include<cstring>
#include<queue>
#define INF 99999999
#define MAXN 1200
#define MAXM 12000
#define MIN(a,b) a>b?b:a

using namespace std;

struct HOUSE
{
   int pigs;
   int last;
};
HOUSE house[MAXM];
int m,n;//m表示猪圈数目,n表示顾客数目
int flow;
int map[MAXN][MAXN];
int st,ed;
int cust[MAXN];
int dist[MAXN];
int BFS()
{
   memset(dist,-1,sizeof(dist));
   int i,tmp;
   dist[st]=0;//汇点n+1的层次为0
   queue<int> q;
   q.push(st);
   while(!q.empty())
   {
	   tmp=q.front();
	   q.pop();
	   for(i=0;i<=ed;i++)
	   {
	      if(dist[i]==-1&&map[tmp][i]>0)
		  {
		     dist[i]=dist[tmp]+1;
			 q.push(i);
		  }
	   }
   }
   if(dist[ed]>0)
	   return 1;
   return 0;
}

int DFS(int x,int low)
{
    int i,a;
	if(x==ed)
		return low;
	for(i=0;i<=ed;i++)
	{
	   if(map[x][i]>0&&dist[i]==dist[x]+1&&(a=DFS(i,MIN(low,map[x][i]))))
	   {
	      map[x][i]-=a;
		  map[i][x]+=a;
		  return a;
	   }
	}
	return 0;
}
void Dinic()
{
    int res;
	while(BFS())
	{
	    while((res=DFS(0,INF)))
			flow+=res;
	}
	return ;
}

int main()
{
	int key,open;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(map,0,sizeof(map));
		memset(cust,0,sizeof(cust));
		st=0;      //源点
		ed=n+1;    //汇点
	   for(int i=1;i<=m;i++)
	   {
	      scanf("%d",&house[i].pigs);
		  house[i].last=0;
	   }
	   for(int i=1;i<=n;i++)
	   {
	       scanf("%d",&key);
		   for(int j=0;j<key;j++)
		   {
		       scanf("%d",&open);
			   if(!house[open].last)
			   {
				   map[st][i]+=house[open].pigs;//如果这个猪圈是第一次被访问,则边权是猪圈原有的猪的数量
				   house[open].last=i;     //记录此时客人的标号
			   }
			   else
			   {
				   map[house[open].last][i]=INF;//如果此猪圈之前已经被访问,则当前顾客和之前顾客之间建立边权为INF的边
				   house[open].last=i;
			   }
		   }
		   scanf("%d",&cust[i]);
		   map[i][ed]=cust[i];//ed为汇点,当前顾客和汇点建立边权为顾客所需的猪的数量的边
	   }
	   flow=0;
	   Dinic();
	   printf("%d\n",flow);
	}
   return 0;
}
//SAP怎么都过不了啊,郁闷。

/*
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 99999999
#define MAXN 1200
#define MAXM 12000
#define MIN(a,b) a>b?b:a

using namespace std;

struct HOUSE
{
   int pigs;
   int last;
};
HOUSE house[MAXM];
int m,n;//m表示猪圈数目,n表示顾客数目
int maxflow;
int map[MAXN][MAXN];
int st,ed;
int cust[MAXN];
int dist[MAXN];
int gap[MAXN];
int pre[MAXN];
void BFS(int ed)
{
   memset(dist,-1,sizeof(dist));
   memset(gap,0,sizeof(gap));
   int i;
   dist[ed]=0;//汇点n+1的层次为0
   gap[dist[ed]]++;
   queue<int> q;
   q.push(ed);
   while(!q.empty())
   {
	   int tmp=q.front();
	   q.pop();
	   for(i=0;i<=ed;i++)
	   {
	      if(dist[i]==-1&&map[i][tmp]>0)
		  {
		     dist[i]=dist[tmp]+1;
			 gap[dist[i]]++;
			 q.push(i);
		  }
	   }
   }
}

void SAP(int st,int ed)
{
   BFS(ed);
   //memset(pre,-1,sizeof(pre));
   int top,aug=INF,i,j,k,flag,mindis;
   top=pre[st]=st;
   //gap[0]=n+2;
   while(dist[st]<ed+1)
   {
	   flag=0;
      for(i=0;i<=ed;i++)
	  {
	     if(map[top][i]>0&&dist[top]==dist[i]+1)
		 {
			 flag=1;
		     break;
		 }
	  }
		 if(flag)
		 {
		    aug=MIN(aug,map[top][i]);
			pre[i]=top;
			top=i;
			if(top==ed)
			{
			   maxflow+=aug;
			   j=top;
			   while(j!=st)
			   {
			      k=pre[j];
				  map[k][j]-=aug;
				  map[j][k]+=aug;
				  j=k;
			   }
			   top=st;
			   aug=INF;
			}
		 }
		 else
		 {
			gap[dist[top]]--;
			if(gap[dist[top]]==0)
				return;
		    mindis=ed+10;
			for(j=0;j<=ed;j++)
			{
			   if(map[top][j]>0&&mindis>dist[j]+1)
				   mindis=dist[j]+1;
			}
			dist[top]=mindis;
			gap[dist[top]]++;
			if(st!=top)
			top=pre[top];
		 }
	}
   return ;
}

int main()
{
	int key,open;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(map,0,sizeof(map));
		memset(cust,0,sizeof(cust));
		st=0;
		ed=n+1;
	   for(int i=1;i<=m;i++)
	   {
	      scanf("%d",&house[i].pigs);
		  house[i].last=-1;
	   }
	   for(int i=1;i<=n;i++)
	   {
	       scanf("%d",&key);
		   for(int j=0;j<key;j++)
		   {
		       scanf("%d",&open);
			   if(house[open].last==-1)
			   {
				   map[st][i]+=house[open].pigs;
				   house[open].last=i;
			   }
			   else
			   {
				   map[house[open].last][i]=INF;
				   house[open].last=i;
			   }
		   }
		   scanf("%d",&cust[i]);
		   map[i][ed]=cust[i];
	   }
	   maxflow=0;
	   SAP(st,ed);
	   printf("%d\n",maxflow);
	}
   return 0;
}
*/


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值