想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:有F种食物,D种饮料
N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份)
一种食物被一头牛吃了之后,其余牛就不能吃了
第一行有N,F,D三个整数
接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类
要求输出最多分配能够满足的牛的数量
解题思路:建图,有2*n+f+d+2个顶点
0表示源点,2*n+f+d+1表示汇点
由源点指向食物,再由食物指向牛,牛再指向对应的饮料,饮料再指向汇点
当然要使每一头牛都对应每一份食物与饮料,所以应该牛i指向牛i再指向饮料,这样就可以避免一头牛只占用多份食物与饮料了
全部是有向的边,而且权值全部为1
我在这里是1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点
/*
dinic
Memory 836K
Time 47MS
*/
#include <iostream>
#include <queue>
using namespace std;
#define MAXV 410
#define INF INT_MAX
#define min(a,b) (a>b?b:a)
int res[MAXV][MAXV]; //残量
int dis[MAXV]; //表示多少层
int source,sink,n,maxflow; //n为总的点数
int bfs(){
int k;
queue<int> q;
memset(dis,-1,sizeof(dis));
dis[sink]=0;
q.push(sink);
while(!q.empty()){
k=q.front();
q.pop();
for(int i=0;i<n;i++){
if(dis[i]==-1 && res[i][k]){
dis[i] = dis[k] + 1;
q.push(i);
}
}
if(k==source) return 1;
}
return 0;
}
int dfs(int cur,int cp){
if(cur==sink) return cp;
int tmp=cp,t;
for(int i=0;i<n && tmp;i++){
if(dis[i]+1==dis[cur] && res[cur][i]){
t=dfs(i,min(res[cur][i],tmp));
res[cur][i]-=t;
res[i][cur]+=t;
tmp-=t;
}
}
return cp-tmp;
}
void dinic(){
maxflow=0;
while(bfs()) maxflow+=dfs(source,INF);
}
int main(){
int f,d;
int i,j,f_sum,d_sum,tmp;
while(~scanf("%d%d%d",&n,&f,&d)){
memset(res,0,sizeof(res));
source=0,sink=2*n+f+d+1;
for(i=1;i<=f;i++) res[source][i]=1; //源点指向食物
for(i=1;i<=d;i++) res[2*n+f+i][sink]=1; //饮料指向汇点
for(i=1;i<=n;i++) res[f+i][f+n+i]=1; //牛指向牛
//点的顺序,食物,奶牛,饮料
for(i=1;i<=n;i++){
scanf("%d%d",&f_sum,&d_sum);
for(j=1;j<=f_sum;j++){
scanf("%d",&tmp);
res[tmp][f+i]=1; //食物指向牛
}
for(j=1;j<=d_sum;j++){
scanf("%d",&tmp);
res[i+f+n][2*n+f+tmp]=1; //牛指向饮料
}
}
n=sink+1; //代表总的点数了
dinic();
printf("%d\n",maxflow);
}
return 0;
}
===========================================================
/*
sap
Memory 828K
Time 32MS
*/
#include<iostream>
using namespace std;
#define MAXV 410
#define INF INT_MAX
#define min(a,b) (a>b?b:a)
int res[MAXV][MAXV],source,sink,n;
int pre[MAXV],dis[MAXV],gap[MAXV],maxflow,cur[MAXV];
int sap(){
int s=source,t=sink;
memset(cur,0,sizeof(cur));
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
int u=pre[s]=s,aug=INF,v;
maxflow=0;
gap[source]=n;
while(dis[s]<n){
loop:
for(v=cur[u];v<n;v++)
if(res[u][v] && dis[u]==dis[v]+1){
cur[u]=v;
aug=min(aug,res[u][v]);
pre[v]=u;
u=v;
if(v==t){
maxflow+=aug;
for(u=pre[u];v!=s;v=u,u=pre[u]) res[u][v]-=aug,res[v][u]+=aug;
aug=INF;
}
goto loop;
}
int mind=n;
for(v=0;v<n;v++)
if(res[u][v]&&(mind>dis[v])){
cur[u]=v;
mind=dis[v];
}
if((--gap[dis[u]])==0) break;
gap[dis[u]=mind+1]++;
u=pre[u];
}
return maxflow;
}
int main(){
int f,d;
int i,j,f_sum,d_sum,tmp;
while(~scanf("%d%d%d",&n,&f,&d)){
memset(res,0,sizeof(res));
source=0,sink=2*n+f+d+1;
for(i=1;i<=f;i++) res[source][i]=1; //源点指向食物
for(i=1;i<=d;i++) res[2*n+f+i][sink]=1; //饮料指向汇点
for(i=1;i<=n;i++) res[f+i][f+n+i]=1; //牛指向牛
//点的顺序,食物,奶牛,饮料
for(i=1;i<=n;i++){
scanf("%d%d",&f_sum,&d_sum);
for(j=1;j<=f_sum;j++){
scanf("%d",&tmp);
res[tmp][f+i]=1; //食物指向牛
}
for(j=1;j<=d_sum;j++){
scanf("%d",&tmp);
res[i+f+n][2*n+f+tmp]=1; //牛指向饮料
}
}
n=sink+1; //代表总的点数了
sap();
printf("%d\n",maxflow);
}
return 0;
}