BZOJ2597 WC2007剪刀石头布(费用流)
考虑使非剪刀石头布情况尽量少。设第i个人赢了xi场,那么以i作为赢家的非剪刀石头布情况就为xi(xi-1)/2种。那么使Σxi(xi-1)/2尽量小即可。
考虑网络流。将比赛建成一排点,人建成一排点,每场未确定比赛向比赛双方连边,确定比赛向赢者连边,这样就是一种合法的比赛方案了。
在此基础上控制代价最小。由于每多赢一场非剪刀石头布情况的增量就更大,将边拆开费用设为增量即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 110 #define S 0 #define T 10101 int n,p[N*N],l[N*N],r[N*N],cnt,t=-1,ans,a[N][N]; int d[N*N],q[N*N],pre[N*N]; bool flag[N*N]; struct data{int to,nxt,cap,flow,cost; }edge[N*N<<4]; void addedge(int x,int y,int z,int cost) { t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,edge[t].cost=cost,p[x]=t; t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,edge[t].cost=-cost,p[y]=t; } int inc(int &x){x++;if (x>T) x-=T;return x;} bool spfa() { memset(d,42,sizeof(d));d[S]=0; memset(flag,0,sizeof(flag)); int head=0,tail=1;q[1]=S; do { int x=q[inc(head)];flag[x]=0; for (int i=p[x];~i;i=edge[i].nxt) if (d[x]+edge[i].cost<d[edge[i].to]&&edge[i].flow<edge[i].cap) { d[edge[i].to]=d[x]+edge[i].cost; pre[edge[i].to]=i; if (!flag[edge[i].to]) q[inc(tail)]=edge[i].to,flag[edge[i].to]=1; } }while (head!=tail); return d[T]<=10000000; } void ekspfa() { while (spfa()) { int v=1; for (int i=T;i!=S;i=edge[pre[i]^1].to) if (edge[pre[i]].flow==edge[pre[i]].cap) {v=0;break;} if (v) for (int i=T;i!=S;i=edge[pre[i]^1].to) ans-=edge[pre[i]].cost,edge[pre[i]].flow++,edge[pre[i]^1].flow--; } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj2597.in","r",stdin); freopen("bzoj2597.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif cnt=n=read(); memset(p,255,sizeof(p)); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { int x=read(); if (i<j) { cnt++;l[cnt]=i,r[cnt]=j; addedge(S,cnt,1,0); if (x==0) addedge(cnt,j,1,0); else if (x==1) addedge(cnt,i,1,0); else addedge(cnt,i,1,0),addedge(cnt,j,1,0); } } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) addedge(i,T,1,j-1); ans=n*(n-1)*(n-2)/6; ekspfa(); cout<<ans<<endl; for (int i=n+1;i<=cnt;i++) for (int j=p[i];~j;j=edge[j].nxt) if (edge[j].flow>0) if (edge[j].to==l[i]) a[l[i]][r[i]]=1;else a[r[i]][l[i]]=1; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) printf("%d ",a[i][j]); printf("\n"); } return 0; }