转载于:https://blog.csdn.net/xiaozhuaixifu/article/details/11300851
题目;http://poj.org/problem?id=3281
思路:将牛拆开,分别一一对应,然后构建有向图:
S(源点) 食物(1-F) 牛(1——N) 牛(1-N) 饮料(1-D) 汇点T
单向边,每条边容量为1 ,转换为最大流问题:
至于为什么要把对应的牛拆成两个顶点:保证一条牛不会被分配多组食物和饮料
代码:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=101;
bool likeF[MAXN][MAXN]; //食物的喜好
bool likeD[MAXN][MAXN];
const int MAXV=MAXN*4+2;
int c[MAXV][MAXV],N,F,D; //c:邻接矩阵
bool visited[MAXV];
int pre[MAXV];
bool bfs(int s,int t)
{
memset(visited,0,sizeof(visited));
queue<int> que;
que.push(s);
visited[s]=1;
while(!que.empty())
{
int p=que.front();
que.pop();
for(int i=0;i<=t;i++)
{
if( !visited[i]&& c[p][i]>0){
que.push(i);
visited[i]=1;
pre[i]=p;
if(i==t) return 1;
}
}
}
return 0;
}
int ek(int s,int t)
{
int max_flow=0;
while(1)
{
if(!bfs(s,t)) break;
int i=t;
while(i!=s)
{
c[pre[i]][i]-=1;
c[i][pre[i]]+=1;
i=pre[i];
}
max_flow++;
}
return max_flow;
}
void solve()
{
// 0:N-1 食物一侧的牛
// N:2N-1 饮料一侧的牛
// 2N:2N+F-1 食物
// 2N+F:2N+F+D-1 饮料
// 构建图模型
int s=N*2+F+D,t=s+1;
for(int i=0;i<F;i++){ //s与食物之间连边
c[s][2*N+i]=1;
}
for(int i=0;i<D;i++){ //饮料和t之间连边
c[2*N+F+i][t]=1;
}
for(int i=0;i<N;i++){
c[i][i+N]=1;
for(int j=0;j<F;j++){
if(likeF[i][j]) c[2*N+j][i]=1;
}
for(int j=0;j<D;j++){
if(likeD[i][j]) c[i+N][j+2*N+F]=1;
}
}
cout<<ek(s,t)<<endl;
}
int main()
{
while(cin>>N>>F>>D)
{
memset(likeD,0,sizeof(likeD));
memset(likeF,0,sizeof(likeF));
for(int i=0;i<N;i++){
int fn,dn;
cin>>fn>>dn;
for(int j=0;j<fn;j++) {
int f;
cin>>f;
likeF[i][f-1]=1;
}
for(int j=0;j<dn;j++){
int d;
cin>>d;
likeD[i][d-1]=1;
}
}
memset(c,0,sizeof(c));
solve();
}
return 0;
}