网络流(最大流)的经典题,今天打个人赛遇到了,具体的见图方法在挑战程序设计的235页。
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<iostream>
#include<vector>
using namespace std;
const int maxn =1010;
const int INF = 99999999;
int N,F,D;
int likeF[maxn][maxn],likeD[maxn][maxn];
struct edge
{
int to,cap,rev;
};
vector<edge>G[maxn];
bool used[maxn];
void add_edge(int from,int to,int cap)
{
edge a;
a.to=to,a.cap=cap,a.rev=G[to].size();
G[from].push_back(a);
a.to=from,a.cap=0,a.rev=G[from].size()-1;
G[to].push_back(a);
}
int dfs(int v,int t,int f)
{
if(v==t)
return f;
used[v]=true;
for(int i=0; i<G[v].size(); i++)
{
edge &e= G[v][i];
if(!used[e.to]&&e.cap>0)
{
int d=dfs(e.to,t,min(f,e.cap));
if(d>0)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
for(;;)
{
memset(used,0,sizeof(used));
int f=dfs(s,t,INF);
if(f==0)return flow;
flow+=f;
}
}
void solve()
{
int s=N*2+F+D,t=s+1;
for(int i=0; i<F; i++)
{
add_edge(s,N*2+i,1);
}
for(int i=0; i<D; i++)
{
add_edge(N*2+F+i,t,1);
}
for(int i=0; i<N; i++)
{
add_edge(i,N+i,1);
for(int j=0; j<F; j++)
if(likeF[i][j])add_edge(N*2+j,i,1);
for(int j=0; j<D; j++)
if(likeD[i][j])add_edge(N+i,N*2+F+j,1);
}
printf("%d\n",max_flow(s,t));
}
int main()
{
while(~scanf("%d%d%d",&N,&F,&D))
{
for(int i=0; i<N; i++)
{
int a,b;
scanf("%d%d",&a,&b);
for(int j=0; j<a; j++)
{
int f;
scanf("%d",&f);
likeF[i][f-1]=1;//牛喜欢的食物
}
for(int j=0; j<b; j++)
{
int f;
scanf("%d",&f);
likeD[i][f-1]=1;//牛喜欢的饮料
}
}
solve();
}
return 0;
}