BZOJ2597: [Wc2007]剪刀石头布
BZOJ2597: [Wc2007]剪刀石头布
https://lydsy.com/JudgeOnline/problem.php?id=2597
分析:
- 好题。
- 先是补集转化,求最少的非剪刀石头布情况。
- 我们枚举那个赢了两次的人,可知总数就是\(\sum\limits _ {i=1}^{n}\binom{w_i}{2}\)其中\(w_i\)为获胜场数。
- 那么对于没打过比赛的两个人,新建点\(tot\),\(S\rightarrow tot\) \(tot\)指向那两个点。
- 然后每个人向\(T\)连\(n\)边,费用为\(\binom{i}{2}-\binom{i-1}{2}\)
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <set>
using namespace std;
#define N 11050
#define M 500050
#define inf 0x3f3f3f3f
const int S=N-1,T=N-2;
int head[N],to[M],nxt[M],flow[M],val[M],n,cnt=1;
int dis[N],Q[N],path[N],vis[N];
inline void add(int u,int v,int f,int c) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=c;
to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-c;
}
bool spfa() {
memset(path,0,sizeof(path));
memset(dis,0x3f,sizeof(dis));
int l=0,r=0;
Q[r++]=S; dis[S]=0;
while(l!=r) {
int x=Q[l++]; if(l==S) l=0;
int i; vis[x]=0;
for(i=head[x];i;i=nxt[i]) if(dis[to[i]]>dis[x]+val[i]&&flow[i]) {
dis[to[i]]=dis[x]+val[i]; path[to[i]]=i^1;
if(!vis[to[i]]) {
vis[to[i]]=1; Q[r++]=to[i]; if(r==S) r=0;
}
}
}
return path[T]!=0;
}
int ek() {
int minc=0;
while(spfa()) {
int nf=inf;
int i;
for(i=T;i!=S;i=to[path[i]]) {
nf=min(nf,flow[path[i]^1]);
}
for(i=T;i!=S;i=to[path[i]]) {
flow[path[i]^1]-=nf;
flow[path[i]]+=nf;
minc+=nf*val[path[i]^1];
}
}
return minc;
}
int A[105][105],pp[105][105];
int main() {
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&A[i][j]);
int tot=n;
for(i=1;i<=n;i++) {
for(j=i+1;j<=n;j++) if(A[i][j]==2) {
tot++;
add(tot,i,1,0);
pp[i][j]=cnt-1;
add(tot,j,1,0);
pp[j][i]=cnt-1;
add(S,tot,1,0);
}
}
for(i=1;i<=n;i++) {
int c=0;
for(j=1;j<=n;j++) {
if(A[i][j]==1) c++;
}
if(c) add(S,i,c,0);
}
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++) {
add(i,T,1,j*(j-1)/2-(j-1)*(j-2)/2);
}
}
int ans=ek();
ans=n*(n-1)*(n-2)/6-ans;
printf("%d\n",ans);
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++) {
if(A[i][j]!=2) {
printf("%d ",A[i][j]);
}else {
if(i==j) printf("0 ");
else {
if(!flow[pp[i][j]]) printf("1 ");
else printf("0 ");
}
}
}
puts("");
}
}