题目链接:http://poj.org/problem?id=1149
大意:有M个猪圈,每个猪圈关着一定数量的猪,作为管理员的Mirko,竟然没有猪圈的钥匙,钥匙在哪呢,有N个顾客,每个顾客拿着其中几个猪圈的钥匙(作为管理员没有钥匙,竟然在顾客的手里,有点难以理解啊,但这不是重点),顾客可以在这些猪圈里购买需要数量的猪,当顾客把猪圈打开购买猪后(不会再关掉),Mirko可以任意将某个开着的猪圈里的猪移动到另一个开着的猪圈里,问Mirko该如何做,能够卖出去最多数量的猪。
解题思路:该题归属于网络流方面的题,难点在于如何构建网络,在网上看到一种很巧妙的构图方法,构图思路如下:
1.取超级源点和超级汇点;
2.当猪圈被第一次打开时,在源点与当前顾客之间连接一条边,容量为该猪圈的猪的头数;
3.当某个猪圈 不是被第一次打开时,在上一个打开该猪圈的顾客与当前打开该猪圈的顾客之间连接一条边,容量为无穷大;
4.在每个顾客与汇点之间连接一条边,容量为该顾客要买猪的头数。
构图完成后套用Edmonds-Karp算法的模版即可,当然用Dinic算法也可以解出。
Edmonds-Karp解法:
#include<stdio.h>
#include<string.h>
#define inf 0x7fffffff
int cap[1005][1005],flow[1005][1005];
int pre[1005],dis[1005];
int que[100000];
int min(int x,int y)
{
return x<y ? x : y;
}
int EK(int s,int t)//s代表源点,t代表汇点
{
int i,temp;
int ans=0;
int head=0,tail=0;
memset(flow,0,sizeof(flow));
while(1)
{
memset(pre,0,sizeof(pre));
memset(dis,0,sizeof(dis));
dis[0]=inf;
que[tail]=0;
tail++;
pre[0]=0;
while(head != tail)
{
temp=que[head];
head++;
for(i=0;i<=t;i++)
{
if(!dis[i] && flow[temp][i] < cap[temp][i])
{
dis[i] = min(dis[temp],cap[temp][i]-flow[temp][i]);
pre[i]=temp;
que[tail]=i;
tail++;
}
}
}
if(dis[t] == 0)
break;
for(i=t;i!=s;i=pre[i])
{
flow[pre[i]][i] += dis[t];
flow[i][pre[i]] -= dis[t];
}
ans += dis[t];
}
return ans;
}
int main()
{
int i,j;
int M,N,k,key;
int pigs[1005];
int visted[1005];
memset(cap,0,sizeof(cap));
memset(visted,0,sizeof(visted));
scanf("%d%d",&M,&N);
for(i=1;i<=M;i++)
scanf("%d",&pigs[i]);
for(i=1;i<=N;i++)
{
scanf("%d",&k);
for(j=1;j<=k;j++)
{
scanf("%d",&key);
if(!visted[key])
cap[0][i] += pigs[key];//源点为0,当某个猪圈第一次打开时,在源点与顾客之间建立边
else
cap[visted[key]][i]=inf;//猪圈不是第一次打开,在该顾客与上一个打开该猪圈的顾客之间建立边
visted[key]=i;
}
scanf("%d",&key);
cap[i][N+1] = key;//汇点为N+1,在顾客与汇点之间建立边
}
printf("%d\n",EK(0,N+1));
return 0;
}