zoukankan      html  css  js  c++  java
  • bzoj2597: [Wc2007]剪刀石头布

    直接求不好求引入未知数,考虑采用补集转化

    对于一次非剪刀石头布的情况,定是一个人赢了另两个人

    若知道一个人共赢了多少人,那么就贡献了n*(n-1)/2种不同的情况

    更一般的,一个人如果多赢了一个人,他的新增的贡献就是他当前没有加上这个人时已经赢了的人

    费用流。

    st->比赛->人->ed,费用是递增的,对于人拆点,一条一条不同费用的连

    我真是震惊了暴力跑得比费用流还快。。。ORZ bzoj14年就踩崩这题的test_tset在discuss教我迭代

    ta没回我之前我脑洞大开写了一发模拟退火,效果极差,我想了一手随机处理2的顺序直接贪心,发现和正确答案已经很接近了,导致退火完全跳不出来。。。

    然后这个大佬的做法:

    实践中这个做法比我的网络流快了1倍不止(或许是修正主义在作祟???)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int inf=(1<<30);
    
    struct node
    {
        int x,y,c,d,next;
    }a[410000];int len,last[11000];
    void ins(int x,int y,int c,int d)
    {
        len++;
        a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
        a[len].next=last[x];last[x]=len;
        
        len++;
        a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
        a[len].next=last[y];last[y]=len;
    }
    
    int st,ed;
    int pre[11000],c[11000],d[11000],ans;
    int list[11000];bool v[11000];
    bool spfa()
    {
        memset(d,63,sizeof(d));d[st]=0;c[st]=inf;
        memset(v,false,sizeof(v));v[st]=true;
        int head=1,tail=2;list[1]=st;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(a[k].c>0&&d[y]>d[x]+a[k].d)
                {
                    d[y]=d[x]+a[k].d;
                    c[y]=min(a[k].c,c[x]);
                    pre[y]=k;
                    if(v[y]==false)
                    {
                        v[y]=true;
                        list[tail]=y;
                        tail++;if(tail==10500)tail=1;
                    }
                }
            }
            v[x]=false;
            head++;if(head==10500)head=1;
        }
        if(d[ed]==d[0])return false;
        else
        {
            int y=ed;ans+=c[ed]*d[ed];
            while(y!=st)
            {
                int k=pre[y];
                a[k].c-=c[ed];
                a[k^1].c+=c[ed];
                y=a[k].x;
            }
            return true;
        }
    }
    
    int mp[110][110],px[11000],py[11000];
    int hw[110],hl[110];
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,z=0,sum=0;
        scanf("%d",&n);
        len=1; 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&mp[i][j]);
                if(i>=j)continue;
                     if(mp[i][j]==1)sum+=hw[i],hw[i]++,hl[j]++;
                else if(mp[i][j]==0)sum+=hw[j],hw[j]++,hl[i]++;
                else z++,px[z]=i,py[z]=j,
                    ins(2*n+z,i,1,0), ins(2*n+z,j,1,0);
            }
        st=2*n+z+1,ed=2*n+z+2;
        for(int i=1;i<=z;i++)ins(st,2*n+i,1,0);
        for(int i=1;i<=n;i++)
        {
            for(int j=hw[i]+1;j<=n-hl[i];j++)
                ins(i,i+n,1,j-1);
            ins(i+n,ed,inf,0);
        }
        
        while(spfa());
        printf("%d
    ",n*(n-1)/2*(n-2)/3-(ans+sum));
        int x,y,g;
        for(int i=2;i<=len;i+=2)
            if(a[i].x>2*n&&a[i].x<=2*n+z)
            {
                g=a[i].x-2*n;
                if(px[g]==a[i].y)x=px[g],y=py[g];
                else x=py[g],y=px[g];
                mp[x][y]=a[i].c^1;
            }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<n;j++)
                printf("%d ",mp[i][j]);
            printf("%d
    ",mp[i][n]);
        }
        
        return 0;
    }
  • 相关阅读:
    递归 正则表达式 杨辉三角
    js 获取浏览器高度和宽度值
    CSS样式大全
    P2501 [HAOI2006]数字序列 (LIS,DP)(未完成)
    Luogu1064 金明的预算方案 (有依赖的背包)
    Luogu2783 有机化学之神偶尔会做作弊 (树链剖分,缩点)
    Luogu5020 货币系统 (完全背包)
    Luogu2798 爆弹虐场 (二分,Kruskal)
    luogu1419 寻找段落 (二分,单调队列)
    Luogu1083 借教室 (线段树)
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10265258.html
Copyright © 2011-2022 走看看