zoukankan      html  css  js  c++  java
  • 「WC 2007」剪刀石头布

    题目链接

    戳我

    (Solution)

    直接求很明显不太好求,于是考虑不构成剪刀石头布的情况。

    我们现在假设一个人(i)赢了(x)场,那么就会有(frac{x*(x-1)}{2})

    我们现在要最小化(frac{x*(x-1)}{2})

    这样就很明显是费用流了吧

    我们先不管费用

    对于每个人向(T)连边,流量为(n)

    (i,j)之间的比赛建立点(y),(s)(y)连边,若比赛结果不确定则将(y)分别向(i)(j)连边。如果确定则向赢的人连边,流量都为(1)

    但是(frac{x*(x-1)}{2})这个花费不太好表示,因为他不是固定的。

    于是可以想到拆边。我们将每个人向(T)连的边拆成(n)条,每条边容量为(1),费用分别为(0,1,2,3...n-1)

    (Code)

    #include<bits/stdc++.h>
    #define rg register
    #define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
    using namespace std;
    const int inf=1e9;
    const int N=1.1e4+5;
    int read(){
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return f*x;
    }
    struct node{
        int to,next,v,w;
    }a[2000001];
    int head[N],cnt=1,n,m,s,t,x,y,z,tot,minx,maxx,dis[N],f[N],pre[10001],fa[10001];
    void add(int x,int y,int c,int v){
        a[++cnt].to=y,a[cnt].next=head[x],a[cnt].v=c,a[cnt].w=v,head[x]=cnt;
        a[++cnt].to=x,a[cnt].next=head[y],a[cnt].v=0,a[cnt].w=-v,head[y]=cnt;
    }
    queue<int>q;
    int spfa(){
        q.push(s);
        memset(dis,127,sizeof(dis));
        memset(f,0,sizeof(f));
        f[s]=1,dis[s]=0;
        int inf=dis[s+1];
        while(!q.empty()){
            int now=q.front();
            q.pop();
            f[now]=0;
            for(int i=head[now];i;i=a[i].next){
                int v=a[i].to;
                if(dis[v]>dis[now]+a[i].w&&a[i].v){
                    dis[v]=dis[now]+a[i].w,pre[v]=i,fa[v]=now;
                    if(!f[v])
                        f[v]=1,q.push(v);
                }
            }
        }
        if(dis[t]!=inf)
            return 1;
        return 0;
    }
    int ans1,ans;
    void answer(){
        while(spfa()){
            int minx=2147483647;
            for(int i=t;i!=s;i=fa[i])
                minx=min(minx,a[pre[i]].v);
            ans+=minx,ans1+=dis[t]*minx;
            for(int i=t;i!=s;i=fa[i])
                a[pre[i]].v-=minx,a[pre[i]^1].v+=minx;
        }
    }
    int M[1001][1001],vis[1001][1001];
    int main(){
        n=read();
        s=0,tot=n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                M[i][j]=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<i;j++){
                tot++,add(s,tot,1,0);
                if(M[i][j]!=1) add(tot,i,1,0),vis[j][i]=cnt-1;
                if(M[i][j]!=0) add(tot,j,1,0),vis[i][j]=cnt-1;
            }
        t=tot+n;
        for(int i=1;i<=n;i++)
            for(int j=0;j<n;j++)
                add(i,t,1,j);
        answer();
        cout<<(n)*(n-1)*(n-2)/6-ans1<<endl;
        for(int i=1;i<=n;i++,cout<<endl)
            for(int j=1;j<=n;j++){
                if(M[i][j]<2) cout<<M[i][j]<<" ";
                else printf("%d ",!vis[i][j]||a[vis[i][j]].v?0:1);
            }
    }
    
  • 相关阅读:
    powershell:clear-item
    windows-杂笔
    powershell:Clear-EventLog
    powershell:Get-ChildItem
    powershell 杂笔
    power-shell:clear-content
    powershell:checkpoint-computer
    vim-缩进设置
    powershell:move-item
    powershell:add-content
  • 原文地址:https://www.cnblogs.com/hbxblog/p/11112246.html
Copyright © 2011-2022 走看看