题目描述

在一些一对一游戏的比赛(如下棋、乒乓球和羽毛球的单打)中,我们经常会遇到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. 在每天黄金时刻将数据库中数据获取包装成Excel表

    过程: 1.由Timer对象实现安排指定的任务在指定的时间进行重复的固定的延迟操作 a.设定时间间隔24小时:PERIOD_DAY = 24 * 60 * 60 * 100; b.指定每天执行操作的时 ...

  2. js数组去重方法包括Es6(方法有很多,但是需要考虑兼容性和数据类型场景)

    1.Es6提供的方法 <script type="text/javascript"> //ES6里新添加了两个方法,set(set是一种新的数据结构,它可以接收一个数组 ...

  3. "xxadmin" user: No protocol specified 错误

    1 查看DISPLAY是否设置:env| grep DISPLAY 如未设置则,export DISPLAY=192.168.0.9:0.0 (斜体字修改为自己的服务器的ip) 2   root用户执 ...

  4. navicate与mysql连接的中文乱码问题

    1. 在navicate中查看 show variables like'char%'; show variables like 'collation_%'; 2.在mysql中查看 通过对比可以发现两 ...

  5. 在Mac里给Terminal终端自定义颜色

    Mac里终端显示默认是一种颜色,太单调了. 然而我们可以自定义这些颜色显示.进入-目录,编辑文件.bash_profile, 输入如下内容: 第三行那些fxfxax看起来是不是像天书?实际上是有规律的 ...

  6. Python学习日志9月16日

    刚才我差点睡着了,差资料的时候太费神,有些累. 今天早晨学习了<head first HTML and CSS>,今天把昨天没看了的关于字体和颜色的一章节看完了,真长.我详细的做了笔记,并 ...

  7. windows/Linux 常用命令

    windows 文件操作命令 cd 切换文件目录 dir 显示文件目录内容 md 创建文件夹 rd 删除文件夹 copy 拷贝文件 move 移动文件 del 删除文件 replace 替换文件 mk ...

  8. Evaluate|GC content|Phred|BAC|heterozygous single nucleotide polymorphisms|estimate genome size|

    (Evaluate):检查reads,可使用比对软件:使用SOAPaligner重新排列:采用massively parallel next-generation sequencing technol ...

  9. java后台验证码的生成

    前台代码: <tr> <td>验证码</td> <td><input name="checkCode" type=" ...

  10. 三. python面向对象

    第七章.面向对象基础 1.面向对象基础 类和对象: a. 创建类 class 类名: def 方法名(self,xxx): pass b. 创建对象 对象 = 类名() c. 通过对象执行方法 对象. ...