题目描述

在一些一对一游戏的比赛(如下棋、乒乓球和羽毛球的单打)中,我们经常会遇到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个人参加一场这样的游戏的比赛,赛程规定任意两个人之间都要进行一场比赛:这样总共有场比赛。比赛已经进行了一部分,我们想知道在极端情况下,比赛结束后最多会发生多少剪刀石头布情况。即给出已经发生的比赛结果,而你可以任意安排剩下的比赛的结果,以得到尽量多的剪刀石头布情况。

输入

输入文件的第1行是一个整数N,表示参加比赛的人数。
之后是一个NN列的数字矩阵:一共N行,每行N列,数字间用空格隔开。
在第(i+1)行的第j列的数字如果是1,则表示i在已经发生的比赛中赢了j;该数字若是0,则表示在已经发生的比赛中i败于j;该数字是2,表示ij之间的比赛尚未发生。数字矩阵对角线上的数字,即第(i+1)行第i列的数字都是0,它们仅仅是占位符号,没有任何意义。
输入文件保证合法,不会发生矛盾,当ij时,第(i+1)行第j列和第(j+1)行第i列的两个数字要么都是2,要么一个是0一个是1。

输出

输出文件的第1行是一个整数,表示在你安排的比赛结果中,出现了多少剪刀石头布情况。
输出文件的第2行开始有一个和输入文件中格式相同的NN列的数字矩阵。第(i+1)行第j个数字描述了ij之间的比赛结果,1表示i赢了j,0表示i负于j,与输入矩阵不同的是,在这个矩阵中没有表示比赛尚未进行的数字2;对角线上的数字都是0。输出矩阵要保证合法,不能发生矛盾。

样例输入

3
0 1 2
0 0 2
2 2 0

样例输出

1
0 1 0
0 0 1
1 0 0


题解

动态加边费用流

首先正着想很难想,考虑反过来:已知最多可能产生的情况个数为$C_n^3$,求最少破坏多少个“剪刀石头布”情况?

然后考虑:对于任意的一个点(一只队伍),如果它有某两条出边,那么就破坏了这三个点之间的“剪刀石头布”情况。

而如果某个点的出度为d,则任意选出两条边的方案数为$C_d^2=\frac{d(d-1)}2$,差分得$C_d^2-C_{d-1}^2=d-1$。

于是我们可以使用使用拆边法来解决问题:S->每条边,容量为1,费用为0;每条边如果是有向边,则向指向发出边的点(赢的队伍),否则指向两个点,容量为1,费用为0。对于每个点,拆出n条边连向T,第i条边的容量为i-1。

然后跑最小费用流出解。由于直接跑会TLE,所以使用动态加边来优化。

最后满流的边指向的队伍就是赢的队伍。

#include <cstdio>
#include <cstring>
#include <queue>
#define N 11000
#define M 2200000
#define pos(i , j) (i - 1) * n + j
using namespace std;
queue<int> q;
int head[N] , to[M] , val[M] , cost[M] , next[M] , cnt = 1 , s , t , dis[N] , from[N] , pre[N] , ans[110][110];
void add(int x , int y, int v , int c)
{
to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt;
}
bool spfa()
{
int x , i;
memset(from , -1 , sizeof(from));
memset(dis , 0x3f , sizeof(dis));
dis[s] = 0 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
if(val[i] && dis[to[i]] > dis[x] + cost[i])
dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]);
}
return ~from[t];
}
int calc(int x)
{
int i;
for(i = head[x] ; i ; i = next[i])
if(!val[i])
return to[i];
return 0;
}
int mincost()
{
int ans = 0 , i , k;
while(spfa())
{
k = 1 << 30;
for(i = t ; i != s ; i = from[i]) k = min(k , val[pre[i]]);
ans += k * dis[t] , add(from[t] , t , 1 , cost[pre[t]] + 1);
for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k;
}
return ans;
}
int main()
{
int n , i , j , x;
scanf("%d" , &n) , s = 0 , t = n * n + n + 1;
for(i = 1 ; i <= n ; i ++ )
{
for(j = 1 ; j <= n ; j ++ )
{
scanf("%d" , &x);
if(i < j)
{
add(s , pos(i , j) , 1 , 0);
if(x != 0) add(pos(i , j) , n * n + i , 1 , 0);
if(x != 1) add(pos(i , j) , n * n + j , 1 , 0);
}
}
}
for(i = 1 ; i <= n ; i ++ )
add(n * n + i , t , 1 , 0);
printf("%d\n" , n * (n - 1) * (n - 2) / 6 - mincost());
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= n ; j ++ )
if(i < j)
x = calc(pos(i , j)) - n * n , ans[x][i + j - x] = 1;
for(i = 1 ; i <= n ; i ++ )
{
for(j = 1 ; j <= n ; j ++ ) printf("%d " , ans[i][j]);
printf("\n");
}
return 0;
}

【bzoj2597】[Wc2007]剪刀石头布 动态加边费用流的更多相关文章

  1. bzoj2879(动态加边费用流)

    参考题解:http://blog.csdn.net/yxuanwkeith/article/details/52254602 //开始跑费用流用的dijkstra,一直错,后来发现动态加边后我不会处理 ...

  2. [bzoj2597][Wc2007]剪刀石头布_费用流

    [Wc2007]剪刀石头布 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 题解: 发现直接求三元环不好求,我们考虑任选三个点不是 ...

  3. BZOJ2597 [Wc2007]剪刀石头布 【费用流】

    题目链接 BZOJ2597 题解 orz思维差 既然是一张竞赛图,我们选出任意三个点都可能成环 总方案数为 \[{n \choose 3}\] 如果三个点不成环,会发现它们的度数是确定的,入度分别为\ ...

  4. bzoj2597: [Wc2007]剪刀石头布(费用流)

    传送门 不得不说这思路真是太妙了 考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样 就是说一个三元组$(a,b,c)$,其中$a$赢两场,$b$赢一场,$c$没有赢 所以如果第$i$个人赢 ...

  5. BZOJ2597 [Wc2007]剪刀石头布(最小费用最大流)

    题目大概是说n个人两两进行比赛,问如何安排几场比赛的输赢使得A胜B,B胜C,C胜A这种剪刀石头布的三元组最多. 这题好神. 首先,三元组总共有$C_n^3$个 然后考虑最小化不满足剪刀石头布条件的三元 ...

  6. BZOJ2597 WC2007剪刀石头布(费用流)

    考虑使非剪刀石头布情况尽量少.设第i个人赢了xi场,那么以i作为赢家的非剪刀石头布情况就为xi(xi-1)/2种.那么使Σxi(xi-1)/2尽量小即可. 考虑网络流.将比赛建成一排点,人建成一排点, ...

  7. bzoj2597: [Wc2007]剪刀石头布

    Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道 ...

  8. 【bzoj2879】[Noi2012]美食节 费用流+动态加边

    原文地址:http://www.cnblogs.com/GXZlegend 题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他 ...

  9. Codeforces 708D 上下界费用流

    给你一个网络流的图 图中可能会有流量不平衡和流量>容量的情况存在 每调整一单位的流量/容量 需要一个单位的花费 问最少需要多少花费使得原图调整为正确(可行)的网络流 设当前边信息为(u,v,f, ...

随机推荐

  1. WebService学习之旅(四)Apache Axis2的安装

    一.Axis2简介 Axis2是目前使用较多的WebService引擎,它是Axis1.x的升级版本,不仅支持SOAP1.1和SOAP1.2,而且也提供了对REST风格WebService的支持. A ...

  2. linux下phpstudy的搭建以及网站的搭建

    step1: 下载SSH连接到IP地址(阿里云上购买的) step2: 安装下载phpstudywget -c http://lamp.phpstudy.net/phpstudy.bin chmod ...

  3. python深浅拷贝问题

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 又叫变量对对象的引用 l ...

  4. Linux下文件以及文件名编码转换

    1.查看文件编码方式--file 文件名(但不是很准确) yang@mint-linux ~ $ file baidu.html baidu.html: HTML document, UTF-8 Un ...

  5. osx launchpad图标的删除

    安装了个parallels desktop之后,OSX中的launchpad中的图标多了不少,可是好多都不是我自己想要的,我们该怎么删除或者修改呢,下面介绍一些方法: ①直接操作Appications ...

  6. poi导出word模板项目实例(一个文件)

    在页面上填写值,然后导出到word模板中,并把页面上的值带到模板中,也就是导出word文档,提前有word 的模板形式, 1.jsp 页面   <table class="formTa ...

  7. flask模板语言

    由于Django的模板引擎和Flask中的Jinja2模板引擎有很多一样的地方,所以我将一样的地方总结到了独立的文章中 https://www.cnblogs.com/kuxingseng95/art ...

  8. ios之UITextfield

    //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 13 ...

  9. 【数学 exgcd】bzoj1407: [Noi2002]Savage

    exgcd解不定方程时候$abs()$不能乱加 Description Input 第1行为一个整数N(1<=N<=15),即野人的数目. 第2行到第N+1每行为三个整数Ci, Pi, L ...

  10. 初涉二维数点问题&&bzoj1935: [Shoi2007]Tree 园丁的烦恼

    离线好评 Description 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草.有一天国王漫步在花园里,若有所思,他问一个 ...