bzoj2597

非常好的网络流题目

首先这里用到了求补集的思想,我们可以先求不满足的三元对的情况

设A-->B代表A赢B

由于最后所有胜负关系都确定,一定是一个完全图,
所以任意一个不合法的三元对,单独取出来一定是1个点出度为2,一个点入度为2,另一点出度1入度1
不妨考虑入度为2的点,从这个点的入边中任意取两条不同的,一定唯一构成一个不合法的三元对
因此合法方案数=C(3,n)-sigma(C(2,in[i]))=C(3,n)+sigma(in[i])/2-sigma(in[i]^2)/2
=C(3,n)+m/2-sigma(in[i]^2)/2=C(3,n)+(n-1)n/4-sigma(in[i]^2)/2
由于前两个是定值,所以我们只要最小化sigma(in[i]^2)/2
不难想到吧每个未确定的关系看做一个点i,s-->i流量为1
i向连接的两个点各连边流量为1的边,费用都为0
关键是点连向t的边,这里与流量二次成正比
考虑到1+3+5+……2n-1=n^2
我们考虑流量n拆成n条流量为1的边,费用依次是1,3,5……2n-1
然后建图跑最小费用流即可
最后求方案也很简单,看做网络流后,找到每个关系的流量流向哪个点即可

  1 const inf=2000000007;
  2 type node=record
  3        next,point,flow,cost:longint;
  4      end;
  5 
  6 var edge:array[0..2000010] of node;
  7     q:array[0..1000010] of longint;
  8     s,p,cur,pre,d:array[0..10010] of longint;
  9     v:array[0..10010] of boolean;
 10     a:array[0..110,0..110] of longint;
 11     x,i,j,n,m,t,len,ans:longint;
 12 
 13 procedure add(x,y,f,c:longint);
 14   begin
 15     inc(len);
 16     edge[len].point:=y;
 17     edge[len].flow:=f;
 18     edge[len].cost:=c;
 19     edge[len].next:=p[x];
 20     p[x]:=len;
 21   end;
 22 
 23 function spfa:boolean;
 24   var x,f,r,i,y:longint;
 25   begin
 26     f:=1;
 27     r:=1;
 28     q[1]:=0;
 29     fillchar(v,sizeof(v),false);
 30     v[0]:=true;
 31     for i:=1 to t do
 32       d[i]:=inf;
 33     d[0]:=0;
 34     while f<=r do
 35     begin
 36       x:=q[f];
 37       v[x]:=false;
 38       i:=p[x];
 39       while i<>-1 do
 40       begin
 41         y:=edge[i].point;
 42         if edge[i].flow>0 then
 43           if d[y]>d[x]+edge[i].cost then
 44           begin
 45             d[y]:=d[x]+edge[i].cost;
 46             pre[y]:=x;
 47             cur[y]:=i;
 48             if not v[y] then
 49             begin
 50               v[y]:=true;
 51               inc(r);
 52               q[r]:=y;
 53             end;
 54           end;
 55         i:=edge[i].next;
 56       end;
 57       inc(f);
 58     end;
 59     if d[t]=inf then exit(false) else exit(true);
 60   end;
 61 
 62 function mincost:longint;
 63   var i,j:longint;
 64   begin
 65     mincost:=0;
 66     while spfa do
 67     begin
 68       i:=t;
 69       mincost:=mincost+d[t];
 70       while i<>0 do
 71       begin
 72         j:=cur[i];
 73         dec(edge[j].flow);
 74         inc(edge[j xor 1].flow);
 75         i:=pre[i];
 76       end;
 77     end;
 78   end;
 79 
 80 function find(x:longint):longint;
 81   var i:longint;
 82   begin
 83     i:=p[x];
 84     while i<>-1 do
 85     begin
 86       if (edge[i].flow=0) and (edge[i].point<>0) then
 87         exit(edge[i].point);  //看流向哪个点,哪个点就输了
 88       i:=edge[i].next;
 89     end;
 90     exit(-1);
 91   end;
 92 
 93 begin
 94   len:=-1;
 95   fillchar(p,sizeof(p),255);
 96   readln(n);
 97   for i:=1 to n do
 98   begin
 99     for j:=1 to n do
100     begin
101       read(a[i,j]);
102       if (i<j) then  //避免重复
103       begin
104         if a[i,j]=2 then
105         begin
106           inc(m);
107           add(0,m+n,1,0);
108           add(n+m,0,0,0);
109           add(m+n,i,1,0);
110           add(i,m+n,0,0);
111           add(m+n,j,1,0);
112           add(j,m+n,0,0);
113         end
114         else if a[i,j]=1 then inc(s[j])
115         else inc(s[i]);
116       end;
117     end;
118     readln;
119   end;
120   t:=m+n+1;
121   ans:=n*(n-1) div 2+n*(n-1)*(n-2) div 3;
122   for i:=1 to n do
123   begin
124     ans:=ans-sqr(s[i]);  //已经有确定的入度k的点就相当于与t相连的前k条边已经满流了
125     for j:=s[i]+1 to n do
126     begin
127       add(i,t,1,j*2-1);
128       add(t,i,0,1-j*2);
129     end;
130   end;
131   ans:=(ans-mincost) div 2;
132   writeln(ans);
133   m:=0;
134   for i:=1 to n-1 do
135     for j:=i+1 to n do
136       if a[i,j]=2 then
137       begin
138         inc(m);
139         x:=find(m+n);
140         if x=i then
141         begin
142           a[i,j]:=0;
143           a[j,i]:=1;
144         end
145         else begin
146           a[i,j]:=1;
147           a[j,i]:=0;
148         end;
149       end;
150 
151   for i:=1 to n do
152   begin
153     for j:=1 to n do
154       write(a[i,j],' ');
155     writeln;
156   end;
157 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473045.html