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;
    }
    
  • 相关阅读:
    JavaScript和ASP.NET的传值
    访问webServices时遇到“测试窗体只能用于来自本地计算机的请求”的解决办法
    使用应用程序访问webservice功能
    利用应用程序访问webservice得到远程数据库数据并上传本地数据
    Win7 Wifi和安卓端连接
    Android项目运行junit测试类时出现错误Internal Error (classFileParser.cpp:3494)的解决办法
    安装Android开发工具及环境配置
    怎样修改注册表,让程序开机自动运行[收藏]
    怎么卸载Apache_pn服务PHPnow使用问题
    【转】mssql中大小写的区分
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10127485.html
Copyright © 2011-2022 走看看