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

         正着求不太好求,,但是不是剪刀石头布的又很好表示:三个人中恰好有一个人赢了两场。 所以我们考虑让这种三元组数量最少使得剪刀石头布最多。

        考虑一个人如果赢了i场,那么他对 非剪刀石头布的三元组的贡献是 -> i(i-1)/2  ,也就是他和任意两个被他击败的人都可以组成三元组。并且每个人的贡献都是独立的,不会有重复(因为一个非法三元组只可能有一个人是赢两局的)。

        所以我们就可以用类似 平方费用 的最小费用流  求解此题了。

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    using namespace std;
    const int maxn=11005;
    const int inf=1<<30;
    vector<int> g[maxn];
    struct lines{
    	int from,to,flow,cap,cost;
    }l[maxn*23];
    int S,T,t=-1,d[maxn],A[maxn],p[maxn];
    int G[105][105],ID[105][105],cnt;
    int n,m,ans,Awin[105];
    bool iq[maxn];
    
    inline void add(int from,int to,int cap,int cost){
    	l[++t]=(lines){from,to,0,cap,cost},g[from].pb(t);
    	l[++t]=(lines){to,from,0,0,-cost},g[to].pb(t);
    }
    
    inline bool SPFA(){
    	queue<int> q;
    	memset(d,0x3f,sizeof(d));
    	d[S]=0,iq[S]=1,q.push(S);
    	A[S]=inf,p[S]=0;
    	int x; lines e;
    	
    	while(!q.empty()){
    		x=q.front(),q.pop();
    		
    		for(int i=g[x].size()-1;i>=0;i--){
    			e=l[g[x][i]];
    			if(e.flow<e.cap&&d[e.to]>d[x]+e.cost){
    				d[e.to]=d[x]+e.cost;
    				A[e.to]=min(A[x],e.cap-e.flow);
    				p[e.to]=g[x][i];
    				if(!iq[e.to]) iq[e.to]=1,q.push(e.to);
    			}
    		}
    		
    		iq[x]=0;
    	}
    
    	if(d[T]==d[T+1]) return 0;
    	ans-=A[T]*d[T];
    	
    	int now=T,pre;
    	while(now!=S){
    		pre=p[now];
    		l[pre].flow+=A[T];
    		l[pre^1].flow-=A[T];
    		now=l[pre].from;
    	}
    	
    	return 1;
    }
    
    inline void MFMC(){
    	while(SPFA());
    }
    
    int main(){
    //	freopen("data.in","r",stdin);
    //	freopen("data.out","w",stdout);
    	
    	scanf("%d",&n),ans=n*(n-1)*(n-2)/6,cnt=n;
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n;j++){
    	    	scanf("%d",&G[i][j]);
    	    	if(i<j){
    	    		if(G[i][j]==2) ID[i][j]=++cnt;
    	    		else if(G[i][j]) Awin[i]++;
    	    		else Awin[j]++;
    			}
    		}
    	S=0,T=cnt+1;
    	
    	for(int i=1;i<=n;i++){
    		ans-=Awin[i]*(Awin[i]-1)>>1;
    	    while(Awin[i]<n-1) add(i,T,1,Awin[i]),Awin[i]++;
    	}
    	
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n;j++) if(ID[i][j]){
    	    	add(S,ID[i][j],1,0);
    	    	add(ID[i][j],i,1,0);
    	    	add(ID[i][j],j,1,0);
    		}
    	
    	MFMC();
    	
    	for(int i=1;i<=n;i++)
    	    for(int j=1,now;j<=n;j++) if(ID[i][j]){
    	        now=ID[i][j];
    	        for(int k=g[now].size()-1;k>=0;k--){
    	        	lines e=l[g[now][k]];
    	        	if(e.flow==1){
    	        		if(e.to==i) G[i][j]=1,G[j][i]=0;
    	        		else G[i][j]=0,G[j][i]=1;
    	        		break;
    				}
    			}
    		}
    	
    	printf("%d
    ",ans);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++) printf("%d ",G[i][j]);
    		puts("");
    	}
    	
    	return 0;
    }
    

      

  • 相关阅读:
    PostgreSQL-14-异常值处理
    Python-5-字符串方法
    Python-6-字典-函数dict,字典的基本操作及将字符串设置功能用于字典
    STP-6-快速生成树协议-新端口角色,状态和类型以及新链路类型
    PostgreSQL-13-缺失值处理
    IP服务-6-SNMP
    IP服务-7-系统日志
    Python-4-设置字符串的格式字符串
    IP服务-5-网络时间协议
    Python -3-列表和元组
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8978819.html
Copyright © 2011-2022 走看看