【网络流-最大流-Dinic-建模】POJ3281 Dining:Pascal 解法

来源:互联网 发布:火焰喷射器升级数据 编辑:程序博客网 时间:2024/04/30 23:54

传送门:POJ3281

【题目大意】

有N头奶牛,每一头都有自己喜欢的食物和饮料,且它们只吃自己喜欢的东西。每头牛只能选一个食物与一个饮料现在有F种食物,D种饮料,求最多能够同时满足几头奶牛的需求。

【输入格式】

第一行N,F,D。N代表牛的数量;F代表食物的数量;D代表饮料的数量

接下来2..N+1行:每行前两个数:F[I]与D[I]代表这头牛喜欢食物与饮料的种类数,接下来F+D行代表他喜欢的食物与饮料。

【输出格式】

一个数X:代表最多几头牛能满足。

【大致思路】

Dinic求最大流+邻接表

【建图思路】

最直白的方式是将食物放在左边,分别与源点相连(容量:1);饮料放在右边,分别与汇点相连(容量:1);每头奶牛看作一个点,放在中间。每头奶牛都与其喜爱的食物和饮料连一条边(容量:MAX),然后求这个图的最大流就行了。

但是,题目有限制每头奶牛只能选一份餐,所以要在这个基础上做限制:将表示牛的点一分为二(牛1和牛2),牛1决定所选的食物(与喜爱食物连边),牛2决定所选饮料(与喜爱饮料连边),两者之间再连一条容量为1的边即可。这个做法让每个牛只能选一种套餐。


【代码】

type  dinic=record    y,r,next,op:longint;  end;var  g:array[-1..20000] of dinic;  level,q,h:array[-1..410] of longint;  n,m,i,ans,a,b,c,j,num,vs,vt,f,d,ff,dd,x:longint;function min(a,b:longint):longint;begin if a>b then exit(b) else exit(a);end;function dfs(v,a:longint):longint;var ans,flow,tmp,u,value:longint;begin if (v=vt) or (a=0) then exit(a); ans:=0;  tmp:=h[v]; while tmp<>0 do begin  u:=g[tmp].y;  value:=g[tmp].r;  if (level[u]=level[v]+1)  then  begin   flow:=dfs(u,min(a,value));   if flow<>0 then   begin    g[tmp].r:=g[tmp].r-flow;    g[g[tmp].op].r:=g[g[tmp].op].r+flow;    ans:=ans+flow;    a:=a-flow;    if a=0 then break;   end;  end;  tmp:=g[tmp].next; end; exit(ans);end;function bfs:boolean;var i,f,r,tmp,v,u,j:longint;begin fillchar(level,sizeof(level),0); f:=1;  r:=1; q[1]:=vs; level[vs]:=1; repeat  v:=q[f];  tmp:=h[v];  while tmp<>0 do  begin   u:=g[tmp].y;   if (g[tmp].r<>0) and (level[u]=0) then   begin    level[u]:=level[v]+1;    inc(r);    q[r]:=u;    if u=vt then exit(true);   end;   tmp:=g[tmp].next;  end; inc(f); until f>r; exit(false);end;procedure add(a,b,c:longint);begin inc(num); g[num].y:=b; g[num].r:=c; g[num].op:=num+1; g[num].next:=h[a]; h[a]:=num; inc(num); g[num].y:=a; g[num].r:=0; g[num].op:=num-1; g[num].next:=h[b]; h[b]:=num;end;procedure init;begin fillchar(h,sizeof(h),0); num:=0; ans:=0; readln(n,f,d); vs:=0; vt:=401; for i:=1 to f do add(vs,i+200,1); for i:=1 to d do add(i+300,vt,1); for i:=1 to n do begin  add(i,i+100,1);  read(ff,dd);  for j:=1 to ff do  begin   read(x);   add(x+200,i,maxlongint);  end;  for j:=1 to dd do  begin   read(x);   add(i+100,x+300,maxlongint);  end;  readln; end;end;procedure main;begin  init;  while bfs do  begin   ans:=ans+dfs(vs,maxlongint);  end;  writeln(ans);end;begin main;end.


0 0
原创粉丝点击