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

    传送门

    解题思路

      考虑全集-不能构成三元环的个数。如果三个点不能构成三元环,一定有一个点的入度为(2),继续扩展,如果一个点的度数为(3),则会失去3个三元环。对于一个点来说,它所产生的不能构成三元环的贡献为(C (deg[x],2)),而度数每增加(1),对于答案的影响就是(C(deg[x]+1,2)-C(deg[x],2)=deg[x]),然后就可以建图了。考虑把边当做点,对于一条未确定的边来说,它只能对两个节点中的一个产生(1)个度数的贡献,所以让每个边向点连流量为1,费用为0的边。然后让源点向每条未确定的边连流量为1,费用为0的边。再让每个点向汇点连流量为(1),费用为(deg[x],deg[x]+1,deg[x]+2,...n)的边。跑一遍费用流。

    代码

    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
     
    using namespace std;
    const int MAXN = 100005;
    const int MAXM = 500005;
    const int inf = 0x3f3f3f3f;
     
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return f?x:-x;
    }
     
    int n,head[MAXN],cnt=1,to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cost[MAXM<<1];
    int deg[MAXN],num,S,T,op[105][105],dis[MAXN],incf[MAXN],pre[MAXN],ans,tmp[105][105];
    bool vis[MAXN];
    queue<int> Q;
     
    inline void add(int bg,int ed,int w,int z){
        to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=w,cost[cnt]=z,head[bg]=cnt;
    }
     
    bool spfa(){
        while(Q.size()) Q.pop();
        memset(dis,0x3f,sizeof(dis));
        memset(vis,false,sizeof(vis));
        Q.push(S);vis[S]=1;incf[S]=inf;dis[S]=0;
        while(Q.size()){
            int x=Q.front();Q.pop();vis[x]=0;
            for(int i=head[x];i;i=nxt[i]){
                int u=to[i];
                if(dis[x]+cost[i]<dis[u] && val[i]){
                    dis[u]=dis[x]+cost[i];
                    incf[u]=min(incf[x],val[i]);
                    pre[u]=i;
                    if(!vis[u]) vis[u]=1,Q.push(u);
                }
            }
        }
        return (dis[T]==inf)?0:1;
    }
     
    inline void update(){
        int x=T,i;
        while(x!=S){
            i=pre[x];
            val[i]-=incf[T];
            val[i^1]+=incf[T];
            x=to[i^1];
        }
        ans-=incf[T]*dis[T];
    }
     
    int main(){
        n=rd();int x;T=n+2;S=n+1;num=T;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                x=rd();op[i][j]=x;
                if(x==1) deg[i]++;
            }
        for(int i=1;i<=n;i++) if(deg[i]>1) ans-=deg[i]*(deg[i]-1)/2;
        for(int i=1;i<=n;i++)
            for(int j=deg[i];j<=n;j++)
                add(i,T,1,j),add(T,i,0,-j);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(op[i][j]==2){
                    num++;add(S,num,1,0);add(num,S,0,0);
                    add(num,i,1,0),add(i,num,0,0);
                    add(num,j,1,0),add(j,num,0,0);
                    tmp[i][j]=tmp[j][i]=num;
                }
        while(spfa()) update();
        ans+=n*(n-1)*(n-2)/6;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)  
                if(op[i][j]==2){
                    for(int k=head[tmp[i][j]];k;k=nxt[k]){
                        if(to[k]==S) continue;
                        if(!val[k]) {
                            if(to[k]==i) op[i][j]=1,op[j][i]=0;
                            else op[j][i]=1,op[i][j]=0;
                        }
                    }
                }
        printf("%d
    ",ans);
        for(int i=1;i<=n;i++){   
            for(int j=1;j<=n;j++)
                printf("%d ",op[i][j]);
            putchar('
    '); 
        }
        return 0;
    }
    
  • 相关阅读:
    [Android Pro] 小心ReleaseByteArrayElements 中的参数问题
    [Android Pro] linux下查看一个文件的属性(ls,lsattr,file,stat)
    [Android Pro] root用户删除文件提示:Operation not permitted
    [Android Pro] adb 进入 recovery, adb 进入 bootloader
    [Android Pro] Android API 23中废弃了HttpClient的解决办法
    [Android Rro] SDK JAR
    [Android Pro] Android下toolbox简介
    [Android Pro] static 和 Volatile 的区别
    [Android Pro] DES加密 version1
    [Android Pro] AES加密
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10127485.html
Copyright © 2011-2022 走看看