
正着求不太好求,,但是不是剪刀石头布的又很好表示:三个人中恰好有一个人赢了两场。 所以我们考虑让这种三元组数量最少使得剪刀石头布最多。
考虑一个人如果赢了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;
}
原文:https://www.cnblogs.com/JYYHH/p/8978819.html