zoukankan      html  css  js  c++  java
  • bzoj2597: [Wc2007]剪刀石头布(费用流)

    传送门

    不得不说这思路真是太妙了

    考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样

    就是说一个三元组$(a,b,c)$,其中$a$赢两场,$b$赢一场,$c$没有赢

    所以如果第$i$个人赢了$w_i$场,那么总共的不能构成的三元组就是$sum_i{w_i*(w_i-1)}{2}$

    最大化满足的数量,就是最小化不满足的数量,就是最小化上面那个式子

    那么我们考虑构建网络流

    建源汇

    对第$i$个人,从它向汇点连容量为$n$的边

    对于每一对$i,j$之间的比赛建一个点$C_{i,j}$,如果这场比赛尚未进行,那么源点向$C_{i,j}$连容$1$费$0$的边,$C_{i,j}向$i$和$j$连容$1$费$0$的边,表示这场比赛只能改变一个点的赢的场数

    我们要最小化上式,那么我们考虑在费用上做文章

    每个点$i$向汇点连边,但因为费用的增加是一次比一次大的,所以我们考虑把这条边拆成$n$条边,容量为$1$费用分别为$0,1,2...$

    因为费用流每一次都先增广最小的费用,所以只要求出最小费用最大流即可

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     9 char buf[1<<21],*p1=buf,*p2=buf;
    10 inline int read(){
    11     #define num ch-'0'
    12     char ch;bool flag=0;int res;
    13     while(!isdigit(ch=getc()))
    14     (ch=='-')&&(flag=true);
    15     for(res=num;isdigit(ch=getc());res=res*10+num);
    16     (flag)&&(res=-res);
    17     #undef num
    18     return res;
    19 }
    20 const int N=50005,M=100005;
    21 int head[N],Next[M],ver[M],edge[M],cost[M],tot=1;
    22 inline void add(int u,int v,int e,int c=0){
    23     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,cost[tot]=c;
    24     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0,cost[tot]=-c;
    25 }
    26 int dis[N],vis[N],cur[N],S,T,ans;
    27 queue<int> q;
    28 bool spfa(){
    29     memset(dis,-1,sizeof(dis));
    30     memset(vis,0,sizeof(vis));
    31     memcpy(cur,head,sizeof(head));
    32     q.push(T),dis[T]=0,vis[T]=1;
    33     while(!q.empty()){
    34         int u=q.front();q.pop(),vis[u]=0;
    35         for(int i=head[u];i;i=Next[i])
    36         if(edge[i^1]){
    37             int v=ver[i],c=cost[i];
    38             if(dis[v]<0||dis[v]>dis[u]-c){
    39                 dis[v]=dis[u]-c;
    40                 if(!vis[v]) vis[v]=1,q.push(v);
    41             }
    42         }
    43     }
    44     return ~dis[S];
    45 }
    46 int dfs(int u,int limit){
    47     if(!limit||u==T) return limit;
    48     int flow=0,f;vis[u]=1;
    49     for(int i=cur[u];i;cur[u]=i=Next[i]){
    50         int v=ver[i];
    51         if(dis[v]==dis[u]-cost[i]&&!vis[v]&&(f=dfs(v,min(limit,edge[i])))){
    52             flow+=f,limit-=f;
    53             edge[i]-=f,edge[i^1]+=f;
    54             ans-=f*cost[i];
    55             if(!limit) break;
    56         }
    57     }
    58     vis[u]=0;
    59     return flow;
    60 }
    61 void zkw(){while(spfa()) dfs(S,inf);}
    62 int mp[105][105],win[105][105],n,cnt;
    63 int main(){
    64     //freopen("testdata.in","r",stdin);
    65     n=read();
    66     for(int i=1;i<=n;++i)
    67     for(int j=1;j<=n;++j)
    68     mp[i][j]=read();
    69     S=0,cnt=n;
    70     for(int i=1;i<=n;++i)
    71     for(int j=1;j<i;++j){
    72         add(S,++cnt,1);
    73         if(mp[i][j]==0||mp[i][j]==2) add(cnt,i,1),win[j][i]=tot-1;
    74         if(mp[i][j]==1||mp[i][j]==2) add(cnt,j,1),win[i][j]=tot-1;
    75     }
    76     T=cnt+1;
    77     for(int i=1;i<=n;++i)
    78     for(int j=0;j<n;++j)
    79     add(i,T,1,j);
    80     ans=n*(n-1)*(n-2)/6;
    81     zkw();
    82     printf("%d
    ",ans);
    83     for(int i=1;i<=n;++i){
    84         for(int j=1;j<=n;++j)
    85         printf("%s%d",j==1?"":" ",!win[i][j]||edge[win[i][j]]?0:1);
    86         putchar(10);
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    Cannot find module 'express'
    txt简单写入
    URLRewriter 伪静态配置Demo
    利用css的sticky特性实现固定首列其他列滚动
    金数据表单接口请求(php)
    Android应用app数据请求捕捉三步走
    go语言模块开发概念与cron定时事务模块的使用
    万维网的发明
    UEditor扩展又拍云图片存储功能实践
    Html5+移动端小应用分享(得见)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9588354.html
Copyright © 2011-2022 走看看