• 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
  • 相关阅读:
    第六节:MySQL字符集和排序规则详解
    .net core中间件修改请求的数据
    Excel根据单元格的内容修改背景色或行背景色
    Excel下拉选择
    notepad++每行末尾或开头插入指定字符串
    .net core通过依赖注入使用log4net记录日志
    7种 Java 设计模式,你会几种?
    微服务技术方案:Spring Cloud 从入门到实战
    OpenCV 进阶应用,用编程手段搞定图像处理
    Vue.js 打造酷炫的可视化数据大屏
  • 原文地址:https://www.cnblogs.com/phile/p/4473045.html
Copyright © 2020-2023  润新知