zoukankan      html  css  js  c++  java
  • Luogu P4249 [WC2007]剪刀石头布

    Link
    先把题意抽象一下:给定一个存在一部分为定向的边的竞赛图,最大化它的三元环个数。
    我们知道竞赛图的三元环个数为({nchoose 3}-sumlimits_{i=1}^n{deg_ichoose 2})
    对于一条未定向的边((u,v)),它会使(u,v)其中一个点的度数加一。
    对于一个点而言,随着度数的增加,度数加一使得三元环减少的个数也是在增加的,也就是说这是一个凸函数。
    那么直接费用流就行了,建图就是凸函数差分的那一套方法。

    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    const int N=107,V=6007,E=50007,inf=1e9;
    int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    int s,t,tot=1,a[N][N],deg[N],head[V],ver[E],next[E],edge[E],cost[E],dis[V],flow[V],inq[V],id[V];std::queue<int>q;struct node{int u,v,id;}p[N*N];
    void add(int u,int v,int f,int c)
    {
        ver[++tot]=v,next[tot]=head[u],head[u]=tot,edge[tot]=f,cost[tot]=c;
        ver[++tot]=u,next[tot]=head[v],head[v]=tot,edge[tot]=0,cost[tot]=-c;
    }
    int spfa()
    {
        memset(dis+1,0x3f,t<<2),q.push(s),inq[s]=1,flow[s]=inf,dis[s]=0,id[t]=-1;
        for(int i,u,v;!q.empty();)
    	for(i=head[u=q.front()],q.pop(),inq[u]=0;i;i=next[i])
    	    if(edge[i]&&dis[v=ver[i]]>dis[u]+cost[i])
    		if(dis[v]=dis[u]+cost[i],id[v]=i,flow[v]=std::min(flow[u],edge[i]),!inq[v])
    		    q.push(v),inq[v]=1;
        return ~id[t];
    }
    int EK()
    {
        int mincost=0;
        for(int p;spfa();) for(mincost+=flow[t]*dis[t],p=t;p^s;p=ver[id[p]^1]) edge[id[p]]-=flow[t],edge[id[p]^1]+=flow[t];
        return mincost;
    }
    int main()
    {
        int n=read(),ans=n*(n-1)*(n-2)/6,cnt=n;s=n*(n+1)/2+1,t=s+1;
        for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=read();
        for(int i=1;i<n;++i) for(int j=i+1;j<=n;++j) if(!a[i][j]) ++deg[j]; else if(a[i][j]==1) ++deg[i]; else add(s,++cnt,1,0),add(cnt,j,1,0),add(cnt,i,1,0),p[cnt]={i,j,tot};
        for(int i=1;i<=n;++i) for(int j=deg[i];j<n;++j) add(i,t,1,j);
        for(int i=1;i<=n;++i) ans-=deg[i]*(deg[i]-1)/2;
        printf("%d
    ",ans-EK());
        for(int i=n+1;i<=cnt;++i) a[p[i].v][p[i].u]=!(a[p[i].u][p[i].v]=edge[p[i].id]);
        for(int i=1;i<=n;++i,puts("")) for(int j=1;j<=n;++j) printf("%d ",a[i][j]);
    }
    
  • 相关阅读:
    迎接2019多校联合新生训练赛(2018/12/31)
    Educational Codeforces Round 57 (Rated for Div. 2) 前三个题补题
    睡学预习(4)
    睡学预习(3)
    Python学习笔记(3)动态类型
    Maya Calendar POJ
    睡学预习(2)——数列极限
    2018-2019赛季多校联合新生训练赛第八场(2018/12/22)补题题解
    蓝桥杯入门题:Hello, world!
    蓝桥杯:P1103
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12657707.html
Copyright © 2011-2022 走看看