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"); } }
相关文章推荐
- BZOJ 2597 WC2007 剪刀石头布 费用流
- BZOJ 2597: [Wc2007]剪刀石头布|费用流
- BZOJ 2597: [Wc2007]剪刀石头布 费用流
- BZOJ 2597: [Wc2007]剪刀石头布 费用流
- BZOJ 2597 [Wc2007]剪刀石头布
- [BZOJ]2597: [Wc2007]剪刀石头布 费用流
- BZOJ 2597 WC2007 剪刀石头布 费用流
- 2597: [Wc2007]剪刀石头布 费用流
- bzoj1449: [JSOI2009]球队收益&&bzoj2597: [Wc2007]剪刀石头布
- 【BZOJ】【P2597】【Wc2007】【剪刀石头布】【题解】【费用流】
- Bzoj2597 [Wc2007]剪刀石头布
- [bzoj2597][WC2007]剪刀石头布
- 【BZOJ2597】【Wc2007】剪刀石头布 费用流,没写zkw卡时过
- BZOJ 2597 [Wc2007]剪刀石头布(凸费用流问题)
- bzoj2597: [Wc2007]剪刀石头布
- [Wc2007]剪刀石头布[补集转化+拆边]
- 【BZOJ2597】[Wc2007]剪刀石头布 最小费用流
- BZOJ2597 [Wc2007]剪刀石头布 【费用流】
- bzoj2597: [Wc2007]剪刀石头布
- 【WC2007】bzoj2597 剪刀石头布