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

    题意

    真是神题。

    题中要求三元环数最多,不妨反着考虑。我们先从(n)个里面选(3)个,有(C_n^3)种方案,之后我们考虑选出的这些方案中最少有几个不能构成三元环。

    考虑三个点不会构成三元环的情况,从入度与出度上考虑,必定是一个点入读和出度都为(1),一个点入度为(2)出度为(0),一个点出度为(2)入度为(0)

    于是从入度考虑。假如有一个点入度为(2),那么会失去一个三元环,即它与连向它的那两个点这种方案。假如一个点入度为(3),那么就会失去3个三元环,即它与连向它的三个点中选两个的所有方案。

    于是我们可以知道:如果一个点(i)的入度为(d_i),那么就会失去(C_{d_i}^2)个三元环。

    我们要给所有未定向的边定向,如果我们定向了一条边(u->v),那么(v)的入度会加(1),我们设(v)原来的入度为(d_v),考虑假如这条边会损失多少三元环,可知为(C_{d_v+1}^2-C_{d_v}^2=d_v)

    于是我们能算出给一个点入度增加(1)产生的代价,我们要使总代价最小,因此可得如下建图方法:

    1.从(S)向每个未定向的边连((1,0))的边。
    2.设当前第(x)个点的入度为(d_x),从每个点(x)向汇点连((1,d_x),(1,d_x+1)...(1,n-2))的边,这样可以表示出(x)入度增加(1)产生的费用。
    3.对于每条未定向的边((u,v)),从该边向(u,v)分别连((1,0))的边。

    之后跑最小费用最大流,输出方案只需判断3.类边是否满流即可。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=110;
    const int maxm=10010;
    const int inf=1e9;
    int n,m,cnt_edge=1,S,T,ans;
    int head[maxn+maxm],in[maxn],dis[maxm+maxn];
    int a[maxn][maxn],pos[maxn][maxn];
    bool vis[maxn+maxm];
    struct Edge{int u,v;}E[maxm];
    struct edge{int to,nxt,flow,cost;}e[maxm*4+maxn*maxn*2];
    inline int read()
    {
    	char c=getchar();int res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    inline void add(int u,int v,int w,int c)
    {
    	e[++cnt_edge].nxt=head[u];
    	head[u]=cnt_edge;
    	e[cnt_edge].to=v;
    	e[cnt_edge].flow=w;
    	e[cnt_edge].cost=c;
    }
    inline void addflow(int u,int v,int w,int c){add(u,v,w,c);add(v,u,0,-c);}
    inline bool spfa()
    {
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        deque<int>q;
        q.push_front(S);dis[S]=0;vis[S]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop_front();vis[x]=0;
            for(int i=head[x];i;i=e[i].nxt)
            {
                int y=e[i].to;
                if(dis[y]>dis[x]+e[i].cost&&e[i].flow>0)
                {
                    dis[y]=dis[x]+e[i].cost;
                    if(!vis[y])
                    {
                        if(q.empty()||dis[y]>dis[q.front()])q.push_back(y);
                        else q.push_front(y);
                        vis[y]=1;
                    }
                }
            }
        }
        return dis[T]!=0x3f3f3f3f;
    }
    int dfs(int x,int lim)
    {
        vis[x]=1;
        if(x==T||lim<=0)return lim;
        int res=lim;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(dis[y]!=dis[x]+e[i].cost||e[i].flow<=0||vis[y])continue;
            int tmp=dfs(y,min(res,e[i].flow));
            res-=tmp;
            e[i].flow-=tmp,e[i^1].flow+=tmp;
            if(res<=0)break;
        }
        return lim-res;
    }
    inline int Dinic()
    {
        int res=0,cost=0;
        while(spfa())
        {
            int flow=dfs(S,inf);
            while(flow>0)
            {
                res+=flow,cost+=flow*dis[T];
                memset(vis,0,sizeof(vis));
                flow=dfs(S,inf);
            }
        }
        return cost;
    }
    int main()
    {
    	//freopen("test.in","r",stdin);
    	//freopen("test.out","w",stdout);
    	n=read();ans=n*(n-1)*(n-2)/6;
    	for(int i=1;i<=n;i++)	
    		for(int j=1;j<=n;j++)
    		{
    			a[i][j]=read();
    			if(a[i][j]==1)in[j]++;
    		}
    	for(int i=1;i<=n;i++)
    		for(int j=i+1;j<=n;j++)
    		{
    			if(a[i][j]!=2)continue;
    			E[++m]=(Edge){i,j};
    		}
    	S=0,T=n+m+1;
    	for(int i=1;i<=m;i++)
    	{
    		addflow(S,i,1,0);
    		addflow(i,E[i].v+m,1,0);pos[E[i].u][E[i].v]=cnt_edge;
    		addflow(i,E[i].u+m,1,0);pos[E[i].v][E[i].u]=cnt_edge;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		ans-=in[i]*(in[i]-1)/2;
    		for(int j=in[i]+1;j<n;j++)addflow(i+m,T,1,j-1);
    	}
    	printf("%d
    ",ans-Dinic());
    	for(int i=1;i<=n;i++,puts(""))
    		for(int j=1;j<=n;j++)
    		{
    			if(a[i][j]<2)printf("%d ",a[i][j]);
    			else printf("%d ",e[pos[i][j]].flow);
    		}
    	return 0;
    }
    
  • 相关阅读:
    Web前段学习索引
    Python学习索引
    Centos7下安装Docker(详细的新手教程)
    Django部署阿里云服务器(nginx+uwsgi)
    (转)Mongo db 与mysql 语法比较
    (转)mongo基本常用命令
    python操作mongodb的基本操作命令
    http响应码
    python回调函数
    Flask框架的使用
  • 原文地址:https://www.cnblogs.com/nofind/p/12115384.html
Copyright © 2011-2022 走看看