POJ3281 Dining (拆点+最大流)
2016-09-04 19:21
381 查看
题意:
N头牛,准备了F种食物,D种饮料,每一头牛会喜欢若干种食物和饮料,但它只能选择一种食物和一种饮料,且每种食物和饮料都只够一头牛选择,问怎样分配能使得食物和饮料都能得到的牛的数量最多,求这个数。
思路:
明显的一道最大流的题目,难点只在怎么建模。建模的方法如下:
1.建立一个超级源,跟每种食物之间连一条容量为1的边;
2.建立一个超级汇,它与每种饮料之间有一条容量为1的边;
3.将每头牛都拆分成两个点C1、C2,两点之间有一条容量为1的边;
4.若一头牛喜欢食物f,就将其对应的C1点与f连接起来,容量为1,若一头牛喜欢饮料d,同理将C2与d连接起来。
为何要拆点?
不拆点不能保证牛只能选择一种食物和一种饮料这一条件。即限定牛结点的容量为1。
我的代码里1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点
N头牛,准备了F种食物,D种饮料,每一头牛会喜欢若干种食物和饮料,但它只能选择一种食物和一种饮料,且每种食物和饮料都只够一头牛选择,问怎样分配能使得食物和饮料都能得到的牛的数量最多,求这个数。
思路:
明显的一道最大流的题目,难点只在怎么建模。建模的方法如下:
1.建立一个超级源,跟每种食物之间连一条容量为1的边;
2.建立一个超级汇,它与每种饮料之间有一条容量为1的边;
3.将每头牛都拆分成两个点C1、C2,两点之间有一条容量为1的边;
4.若一头牛喜欢食物f,就将其对应的C1点与f连接起来,容量为1,若一头牛喜欢饮料d,同理将C2与d连接起来。
为何要拆点?
不拆点不能保证牛只能选择一种食物和一种饮料这一条件。即限定牛结点的容量为1。
我的代码里1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点
#include<cstdio> #include<cstring> using namespace std; const int maxn=500;//点数的最大值 const int maxm=250000;//边数的最大值 const int inf=0x3f3f3f3f; struct Edge { int to,next,cap,flow; }edge[maxm];//注意是maxm int tol; int head[maxn]; int cur[maxn],d[maxn];// 当前弧下标 结点到汇点距离下界 int p[maxn],gap[maxn];//可增广路上的上一条弧 gap优化 //比dinic多的两个数组 void init() { tol=0; memset(head,-1,sizeof(head)); } //加边,单向图三个参数,双向图四个参数 void addedge(int u,int v,int w,int rw=0) { edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u]; edge[tol].flow=0; head[u]=tol++; edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v]; edge[tol].flow=0; head[v]=tol++; } //输入参数:起点、终点、点的总数 //点的编号没有影响,只要输入点的总数 int sap(int s,int t,int N){ memset(gap, 0, sizeof(gap)); memset(d, 0, sizeof(d)); memcpy(cur, head, sizeof(head)); int u=s; p[u]=-1; gap[0]=N; int ans=0; while(d[s]<N){ if(u == t){ int Min=inf; for(int i=p[u]; i!=-1; i=p[edge[i^1].to])//找最小残量值 if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i = p[u]; i!=-1; i=p[edge[i^1].to]){//增广 edge[i].flow+=Min; edge[i^1].flow-=Min; } u=s; ans+=Min; continue; } bool ok=false; int v; for(int i=cur[u]; i!=-1; i=edge[i].next){ v=edge[i].to; if(edge[i].cap-edge[i].flow && d[v]+1==d[u]){//Advance前进 ok=true; cur[u]=p[v]=i; break; } } if(ok){ u=v; continue; } //Retreat走不动了,撤退 int Min=N; for(int i=head[u]; i!=-1; i=edge[i].next) if(edge[i].cap-edge[i].flow && d[edge[i].to] < Min){ Min=d[edge[i].to]; cur[u]=i; } gap[d[u]]--; if(!gap[d[u]])return ans; d[u] = Min+1; gap[d[u]]++; if(u!=s) u=edge[p[u]^1].to;//退一步,沿父边返回 } return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int f,d,n; int fnum,dnum,tmp,source,sink; while(~scanf("%d%d%d",&n,&f,&d)){ init(); source=0;sink=2*n+f+d+1; for(int i=1; i<=f; i++)addedge(source, i, 1);//源点指向食物 for(int i=1; i<=d; i++)addedge(f+2*n+i, sink, 1);//饮料指向汇点 for(int i=1; i<=n; i++)addedge(f+i, f+n+i, 1);//牛指向牛 for(int i=1; i<=n ;i++){ scanf("%d%d",&fnum,&dnum); while(fnum--){ scanf("%d",&tmp); addedge(tmp, f+i, 1);//食物指向牛 } while(dnum--){ scanf("%d",&tmp); addedge(f+n+i, f+2*n+tmp, 1); //牛指向饮料 } } printf("%d\n",sap(source, sink, f+2*n+d+2)); } return 0; }
相关文章推荐
- poj3281 Dining-网络流最大流-多对一的匹配
- poj3281 Dining(经典最大流+拆点)
- POJ3281 Dining 最大流 邻接表[模板]
- POJ3281 Dining 求最大流
- POJ3281 Dining [最大流应用]
- 【poj3281】Dining 最大流
- POJ3281 Dining(拆点构图 + 最大流)
- POJ3281 Dining,最大流EK算法
- (拆点+最大流)POJ3281 Dining
- poj3281 Dining(最大流)
- POJ3281-Dining(最大流)
- POJ3281 Dining 最大流
- 【POJ3281】Dining【最大流】
- poj3281 Dining 最大流
- POJ3281 dining——最大流(建图是重点)
- POJ3281--Dining(最大流)
- 【POJ3281 Dining 】最大流
- poj3281-Dining ,最大流,建图
- POJ3281 Dining(最大流+拆点)
- poj3281 Dining[最大流]