您的位置:首页 > 其它

bzoj 2597: [Wc2007]剪刀石头布

2017-12-28 10:46 417 查看

题意:

在一些一对一游戏的比赛(如下棋、乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况。有的时候,无聊的人们会津津乐道于统计有多少这样的剪刀石头布情况发生,即有多少对无序三元组(A, B, C),满足其中的一个人在比赛中赢了另一个人,另一个人赢了第三个人而第三个人又胜过了第一个人。注意这里无序的意思是说三元组中元素的顺序并不重要,将(A, B, C)、(A, C, B)、(B, A, C)、(B, C, A)、(C, A, B)和(C, B, A)视为相同的情况。

有N个人参加一场这样的游戏的比赛,赛程规定任意两个人之间都要进行一场比赛:这样总共有场比赛。比赛已经进行了一部分,我们想知道在极端情况下,比赛结束后最多会发生多少剪刀石头布情况。即给出已经发生的比赛结果,而你可以任意安排剩下的比赛的结果,以得到尽量多的剪刀石头布情况。

题解:

好久没做网络流相关,感觉什么都不会了。

这题补集思想很重要,直接做不太可做,考虑有多少对是不符合的。

容易发现,当三个点不是三元环是,一定有以个点的出度为2,所以可以得到:

C3n−∑inC2d[i]

d[i]最小。

然后就可以费用流了,st向每场比赛连边流量1,费用0。比赛向选手连边,流量1,费用0。然后每个选手向ed连n条边,流量都为1,费用是c2i的差分。

然后看哪条边满流就是谁赢。

code:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
struct node{
int x,y,c,d,next;
}a[100000];int len=1,last[15000];
int n,map[110][110],num,st,ed,w[110][5],s[15000],q[15000],p[15000];
bool u[15000],c[110][110];
void ins(int x,int y,int c,int d)
{
a[++len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
a[len].next=last[x];last[x]=len;
a[++len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
a[len].next=last[y];last[y]=len;
}
void pre()
{
for(int i=0;i<=n;i++)
{
w[i][0]=1;
for(int j=1;j<=3&&j<=i;j++) w[i][j]=w[i-1][j]+w[i-1][j-1];
}
}
void insert(int x)
{
for(int i=1;i<=n;i++)
ins(x,ed,1,w[i][2]-w[i-1][2]);
}
bool spfa()
{
memset(s,63,sizeof(s));
memset(u,false,sizeof(u));
int l=1,r=2;q[l]=st;s[st]=0;u[st]=true;
while(l!=r)
{
int x=q[l];
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(s[y]>s[x]+a[i].d&&a[i].c>0)
{
s[y]=s[x]+a[i].d;
p[y]=i;
if(!u[y])
{
u[y]=true;q[r]=y;
r++;if(r>ed+1) r=1;
}
}
}
u[x]=false;
l++;if(l>ed+1) l=1;
}
return s[ed]<999999999;
}
int flow()
{
int x=ed;
int ans=0,min=-1;
while(x!=st)
{
int i=p[x];
if (a[i].c<min||min==-1)min=a[i].c;
x=a[i].x;
}
x=ed;
while(x!=st)
{
int i=p[x];
a[i].c-=min;
a[i^1].c+=min;
x=a[i].x;
ans=ans+a[i].d*min;
}
return ans;
}
int main()
{
scanf("%d",&n);
memset(c,false,sizeof(c));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(i<=j) continue;
num++;
if(map[i][j]==2)
{
ins(num+n,i,1,0);ins(num+n,j,1,0);
map[i][j]=len-3;
}
else
{
c[i][j]=true;
if(map[i][j]==1) ins(num+n,i,1,0);
if(map[i][j]==0) ins(num+n,j,2,0);
}
}
pre();
st=0;ed=n+num+1;
for(int i=1;i<=num;i++) ins(st,i+n,1,0);
for(int i=1;i<=n;i++) insert(i);
int ans=0;
while(spfa()) ans+=flow();
printf("%d\n",w
[3]-ans);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i<=j)
{
if(c[j][i]) printf("%d ",1-map[j][i]);
else printf("%d ",a[map[j][i]].c==0?0:1);
}
else
{
if(c[i][j]) printf("%d ",map[i][j]);
else printf("%d ",a[map[i][j]].c==0?1:0);
}
}
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: