题目链接:http://poj.org/problem?id=3281
个人认为这个题的难点就在于见图,应为有多个源点和起点,所以我们可以设置一个超级源点和超级汇点
将牛分1为2,一个牛吃菜,一个牛吃草,两个牛之间一一对应,之间的容量都是1
所以总的节点的个数就是2*n+f+d+2
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#define MAXINT INT_MAX
using namespace std;
const int MAX_N = 500;
const int INF = 100000000;
class edge
{
public:
int flow;//流量
int cap;//容量
edge(int flow,int cap) : flow(flow),cap(cap){}
edge()
{
flow =0;
cap=0;
}
};
edge maps[MAX_N][MAX_N];
int dis[MAX_N];//用于分成
int n,f,d,totaln;
int s,t;
//参数是源点和汇点
bool bfs(int s,int t)
{
int v,i;
queue<int> que;
memset(dis,0,sizeof(dis));
que.push(s);
dis[s] =1;
while(!que.empty())
{
v = que.front();
que.pop();
for(int i=1;i<=totaln;i++)
{
if(!dis[i] && maps[v][i].cap>maps[v][i].flow)
{
que.push(i);//该点的流量还是可以增加的
dis[i] = dis[v] +1;
}
}
//到达终点
if( v==t )
return true;
}
return false;
}
int dfs(int s,int t,int f)
{
if(s==t)
return f;
int temp = f;
int d;
for(int i=1;i<=totaln;i++)
{
if(dis[i]==(dis[s]+1) && temp && maps[s][i].cap>maps[s][i].flow)
{
d = dfs(i,t,min(temp,maps[s][i].cap-maps[s][i].flow));
// cout<<d<<endl;
maps[s][i].flow += d;
maps[i][s].flow -= d;
temp -= d;
}
}
return f-temp;
}
int dinic(int s,int t)
{
int maxflow = 0;
while(bfs(s,t))
{
//cout<<maxflow<<endl;
maxflow += dfs(s,t,INF);
}
return maxflow;
}
//代表奶牛数,菜的数目,汤的数目
void build_graph(int n,int f,int d)
{
totaln = 2*n+f+d+2;
s = 2*n+f+d+1;//源点
t = 2*n+f+d+2;//汇点
// cout<<s<<" "<<t<<endl;
for(int i=1;i<=f;i++)
{
//源点指向食物
maps[s][i].cap=1;
}
for(int i=1;i<=d;i++)
{
//饮料指向汇点
maps[2*n+f+i][t].cap=1;
}
int lf,ld;//喜欢菜的种类数和烫的种类数
for(int i=1;i<=n;i++)
{
//第i头牛
//第第一类牛的第i个指向第二类牛的第i个,可以防止一个牛吃多种食物
maps[f+i][f+i+n].cap=1;
scanf("%d %d",&lf,&ld);
int lff,ldd;//喜欢菜和汤的编号
for(int j = 1;j<=lf;j++)
{
//s食物指向第一类牛
scanf("%d",&lff);
maps[lff][i+f].cap=1;
}
for(int j=1;j<=ld;j++)
{
//由第二类牛指向drink
scanf("%d",&ldd);
maps[i+f+n][n+f+n+ldd].cap=1;
}
}
}
int main()
{
//freopen("最大流_POJ_3281.txt","r",stdin);
while(scanf("%d %d %d",&n,&f,&d)!=EOF)
{
build_graph(n,f,d);
printf("%d\n",dinic(s,t));
}
}