Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 3803 | Accepted: 1723 |
Description
Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.
Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.
Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.
Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).
Input
Output
Sample Input
4 3 3 2 2 1 2 3 1 2 2 2 3 1 2 2 2 1 3 1 2 2 1 1 3 3
Sample Output
3
Hint
Source
以前做的题目,拆点有的是因为是无向图,有的是因为防止回流
这一次这个题目的拆点,是因为每头牛只能吃一个套餐。
这是一个很关键的因素,这个因素也限制了二分图匹配的应用
我不知道哪位高手是用二分图解掉这道题,但我在思考用二分图建图的时候,就受这个条件的制约,转而去寻找用网络流的方法
构图还是比较简单的
很容易就得到左边放食物,右边放饮料
刚开始我用二分图做的时候,就是直接按照牛的喜好,将食物和饮料相连
后来因为二分图这条路走不通,使用SAP的时候,那么关键就变成了满足上面那个每头牛只吃一个套餐的条件了。
那怎么满足呢?
对,就是将牛拆点,拆i,i+f,两个点之间练1,保证每头牛只能吃一次。
其他就是源点连向食物,边长为1;饮料连向汇点,边长为1.
构图就是这样了,比较简单
如果谁知道怎么用二分图过了这道题,跟我说一声,谢了
#include<cstdio>
#include<cstring>
const int N=510;
const int M=100001;
const int inf=0x7fffffff;
int head[N];
struct Edge
{
int v,next,w;
} edge[M];
int cnt,n,s,t;
void addedge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int sap()
{
int pre[N],cur[N],dis[N],gap[N];
int flow=0,aug=inf,u;
bool flag;
for(int i=0; i<n; i++)
{
cur[i]=head[i];
gap[i]=dis[i]=0;
}
gap[s]=n;
u=pre[s]=s;
while(dis[s]<n)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].w<aug) aug=edge[j].w;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].w-=aug;
edge[cur[u]^1].w+=aug;
}
aug=inf;
}
break;
}
}
if(flag) continue;
int mindis=n;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
int f,d;
while(scanf("%d%d%d",&n,&f,&d)!=EOF)
{
int ff,dd;
s=0;
t=d+f+2*n+1;
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=f;i++) addedge(0,i,1);
for(int i=1;i<=n;i++) addedge(i+f,i+n+f,1); //2*n+f
for(int i=1;i<=d;i++) addedge(i+f+2*n,d+f+2*n+1,1);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d%d",&ff,&dd);
for(int j=1;j<=ff;j++)
{
scanf("%d",&x);
addedge(x,i+f,1);
}
for(int j=1;j<=dd;j++)
{
scanf("%d",&x);
addedge(i+n+f,x+f+2*n,1);
}
}
n=d+f+2*n+2;
printf("%d/n",sap());
}
return 0;
}