码迷,mamicode.com
首页 > 其他好文 > 详细

[WC2007] 剪刀石头布

时间:2018-05-02 11:15:24      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:技术   bubuko   nbsp   inf   sizeof   size   front   oid   组成   

技术分享图片

 

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

    考虑一个人如果赢了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\n",ans);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) printf("%d ",G[i][j]);
		puts("");
	}
	
	return 0;
}

  

[WC2007] 剪刀石头布

标签:技术   bubuko   nbsp   inf   sizeof   size   front   oid   组成   

原文地址:https://www.cnblogs.com/JYYHH/p/8978819.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!