首页 > 代码库 > 【BZOJ1305】dance跳舞(最大流,裂点,二分答案)

【BZOJ1305】dance跳舞(最大流,裂点,二分答案)

题意:一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。 有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。 给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

n<=50,k<=30

思路:明显的最大流问题

将每个男,女都裂成两个点,一个表示喜欢,另一个表示不喜欢

二分答案

(S,num[i,1]) 流量为mid

(num[i,4],T) mid

(num[i,1],num[i,2]) (num[i,3],num[i,4]) k

对于互相喜欢的i,j:

(num[i,1],num[j,4]) 1

不喜欢:

(num[i,2],num[j,3]) 1

 判maxflow是否=mid*n即可

  1 var head,gap,dis:array[0..10000]of longint;
  2     vet,next,len,fan:array[1..200000]of longint;
  3     num:array[1..50,1..4]of longint;
  4     a:array[1..50,1..50]of char;
  5     n,m,i,l,r,mid,last,s,source,src,tot,k1,j:longint;
  6     ch:string;
  7 
  8 procedure add(a,b,c:longint);
  9 begin
 10  inc(tot);
 11  next[tot]:=head[a];
 12  vet[tot]:=b;
 13  len[tot]:=c;
 14  head[a]:=tot;
 15  inc(tot);
 16  next[tot]:=head[b];
 17  vet[tot]:=a;
 18  len[tot]:=0;
 19  head[b]:=tot;
 20 end;
 21 
 22 function min(x,y:longint):longint;
 23 begin
 24  if x<y then exit(x);
 25  exit(y);
 26 end;
 27 
 28 function dfs(u,aug:longint):longint;
 29 var e,v,t,val,flow:longint;
 30 begin
 31  if u=src then exit(aug);
 32  e:=head[u]; val:=s-1; flow:=0;
 33  while e<>0 do
 34  begin
 35   v:=vet[e];
 36   if len[e]>0 then
 37   begin
 38    if dis[u]=dis[v]+1 then
 39    begin
 40     t:=dfs(v,min(len[e],aug-flow));
 41     len[e]:=len[e]-t;
 42     len[fan[e]]:=len[fan[e]]+t;
 43     flow:=flow+t;
 44     if dis[source]>=s then exit(flow);
 45     if aug=flow then break;
 46    end;
 47    val:=min(val,dis[v]);
 48   end;
 49   e:=next[e];
 50  end;
 51  if flow=0 then
 52  begin
 53   dec(gap[dis[u]]);
 54   if gap[dis[u]]=0 then dis[source]:=s;
 55   dis[u]:=val+1;
 56   inc(gap[dis[u]]);
 57  end;
 58  exit(flow);
 59 end;
 60 
 61 function maxflow:longint;
 62 var ans:longint;
 63 begin
 64  fillchar(gap,sizeof(gap),0);
 65  fillchar(dis,sizeof(dis),0);
 66  gap[0]:=s; ans:=0;
 67  while dis[source]<s do ans:=ans+dfs(source,maxlongint);
 68  exit(ans);
 69 end;
 70 
 71 procedure build;
 72 var i,j:longint;
 73 begin
 74  fillchar(head,sizeof(head),0);
 75  tot:=0;
 76  for i:=1 to n do
 77  begin
 78   add(num[i,1],num[i,2],k1);
 79   add(num[i,3],num[i,4],k1);
 80  end;
 81  for i:=1 to n do
 82  begin
 83   add(source,num[i,1],mid);
 84   add(num[i,4],src,mid);
 85  end;
 86  for i:=1 to n do
 87   for j:=1 to n do
 88    if a[i,j]=Y then add(num[i,1],num[j,4],1)
 89     else add(num[i,2],num[j,3],1);
 90 end;
 91 
 92 begin
 93  assign(input,bzoj1305.in); reset(input);
 94  assign(output,bzoj1305.out); rewrite(output);
 95  readln(n,k1);
 96  for i:=1 to n do
 97  begin
 98   readln(ch);
 99   for j:=1 to n do a[i,j]:=ch[j];
100  end;
101  for i:=1 to 200000 do
102   if i mod 2=1 then fan[i]:=i+1
103    else fan[i]:=i-1;
104  for i:=1 to n do
105   for j:=1 to 4 do
106   begin
107    inc(s); num[i,j]:=s;
108   end;
109  source:=s+1; src:=s+2; s:=s+2;
110  l:=0; r:=n; last:=0;
111  while l<=r do
112  begin
113   mid:=(l+r)>>1;
114   build;
115   if maxflow>=mid*n then begin last:=mid; l:=mid+1; end
116    else r:=mid-1;
117  end;
118  writeln(last);
119  close(input);
120  close(output);
121 end.

 

【BZOJ1305】dance跳舞(最大流,裂点,二分答案)