考虑使非剪刀石头布情况尽量少。设第i个人赢了x场,那么以i作为赢家的非剪刀石头布情况就为x(x-1)/2种。那么使Σx(x-1)/2尽量小即可。

  考虑网络流。将比赛建成一排点,人建成一排点,每场未确定比赛向比赛双方连边,确定比赛向赢者连边,这样就是一种合法的比赛方案了。

  在此基础上控制代价最小。由于每多赢一场非剪刀石头布情况的增量就更大,将边拆开费用设为增量即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),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=-,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<<];
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=,edge[t].cost=cost,p[x]=t;
t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=,edge[t].flow=,edge[t].cost=-cost,p[y]=t;
}
int inc(int &x){x++;if (x>T) x-=T;return x;}
bool spfa()
{
memset(d,,sizeof(d));d[S]=;
memset(flag,,sizeof(flag));
int head=,tail=;q[]=S;
do
{
int x=q[inc(head)];flag[x]=;
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]=;
}
}while (head!=tail);
return d[T]<=;
}
void ekspfa()
{
while (spfa())
{
int v=;
for (int i=T;i!=S;i=edge[pre[i]^].to)
if (edge[pre[i]].flow==edge[pre[i]].cap) {v=;break;}
if (v)
for (int i=T;i!=S;i=edge[pre[i]^].to)
ans-=edge[pre[i]].cost,edge[pre[i]].flow++,edge[pre[i]^].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,,sizeof(p));
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
{
int x=read();
if (i<j)
{
cnt++;l[cnt]=i,r[cnt]=j;
addedge(S,cnt,,);
if (x==) addedge(cnt,j,,);
else if (x==) addedge(cnt,i,,);
else addedge(cnt,i,,),addedge(cnt,j,,);
}
}
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
addedge(i,T,,j-);
ans=n*(n-)*(n-)/;
ekspfa();
cout<<ans<<endl;
for (int i=n+;i<=cnt;i++)
for (int j=p[i];~j;j=edge[j].nxt)
if (edge[j].flow>)
if (edge[j].to==l[i]) a[l[i]][r[i]]=;else a[r[i]][l[i]]=;
for (int i=;i<=n;i++)
{
for (int j=;j<=n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
return ;
}
05-06 15:36