• [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;
    }
    

      

  • 相关阅读:
    SQL优化总结(转)
    ORA-04030: 在尝试分配...字节(...)时进程内存不足的原因分析解决方法
    MyEclipse 在线安装SVN插件
    jboss+ejb entityManager操作数据库
    struts2标签#、%、$取值
    ejb+weblogic布署(转)
    ejb+jboss集群(转)
    myeclipse配置jboss(转载)
    list-列表练习
    python-循环小练习
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8978819.html
Copyright © 2020-2023  润新知