(拆点+最大流)POJ3281 Dining

来源:互联网 发布:12306手机端网络异常 编辑:程序博客网 时间:2024/05/16 16:34

题目大意是N头牛,准备了F种食物,D种饮料,每一头牛会喜欢若干种食物和饮料,但它只能选择一种食物和一种饮料,且每种食物和饮料都只够一头牛选择,问怎样分配能使得食物和饮料都能得到的牛的数量最多,求这个数。

明显的一道最大流的题目,难点只在怎么建模。建模的方法如下:

1.建立一个超级源,跟每种食物之间连一条容量为1的边;

2.建立一个超级汇,它与每种饮料之间有一条容量为1的边;

3.将每头牛都拆分成两个点C1、C2,两点之间有一条容量为1的边;

4.若一头牛喜欢食物f,就将其对应的C1点与f连接起来,容量为1,若一头牛喜欢饮料d,同理将C2与d连接起来。

为何要拆点?

不拆点不能保证牛只能选择一种食物和一种饮料这一条件。即限定牛结点的容量为1。


至于最大流方面,数据规模不大就选了EK,当然这类题目还有变种,就要考虑其余的算法及优化手段了。


代码如下:

#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;int map[500][500];int pre[500];int n,N,D,F;queue<int>q; bool bfs(int src,int des){memset(pre,-1,sizeof(pre));while (!q.empty()) q.pop();pre[src]=-1;int index;q.push(src);while(!q.empty()){index=q.front();q.pop();for (int i=0;i<=1+n;i++){if (pre[i]==-1 && map[index][i]>0){pre[i]=index;if (i==des)return true;q.push(i);}}}return false;}int maxflow(int src,int des){int maxf=0;while (bfs(src,des)){int minflow=10000000;for (int i=des;i!=src;i=pre[i])minflow=min(minflow,map[pre[i]][i]);for (int i=des;i!=src;i=pre[i]){map[pre[i]][i]-=minflow;map[i][pre[i]]+=minflow;}maxf+=minflow;}return maxf;}int main(){int s=0,t;scanf("%d%d%d",&N,&F,&D);n=N*2+F+D;memset(map,0,sizeof(map));t=n+1;for (int i=1;i<=F;i++)map[s][i]=1;for (int i=1+F+2*N;i<=D+F+2*N;i++)map[i][t]=1;for (int i=1+F;i<=N+F;i++)map[i][i+N]=1;for (int i=1;i<=N;i++){int f,d,id;scanf("%d%d",&f,&d);for (int j=0;j<f;j++){scanf("%d",&id);map[id][i+F]=1;}for (int j=0;j<d;j++){scanf("%d",&id);map[i+F+N][id+F+2*N]=1;}}printf("%d\n",maxflow(s,t));return 0;}

0 0
原创粉丝点击