Description

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

Input

输入文件的第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。

Output

输出文件的第1行是一个整数,表示在你安排的比赛结果中,出现了多少剪刀石头布情况。
输出文件的第2行开始有一个和输入文件中格式相同的NN列的数字矩阵。第(i+1)行第j个数字描述了ij之间的比赛结果,1表示i赢了j,0表示i负于j,与输入矩阵不同的是,在这个矩阵中没有表示比赛尚未进行的数字2;对角线上的数字都是0。输出矩阵要保证合法,不能发生矛盾。
 
PS:这题太牛叉了值得一做……
 
代码(896MS):
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <queue>
  6. using namespace std;
  7.  
  8. const int MAXN = ;
  9. const int MAXV = MAXN * MAXN;
  10. const int MAXE = MAXN * MAXV;
  11. const int INF = 0x7f7f7f7f;
  12.  
  13. struct ZWK_FLOW {
  14. int head[MAXV], dis[MAXV];
  15. int to[MAXE], next[MAXE], flow[MAXE], cost[MAXE];
  16. int n, ecnt, st, ed;
  17.  
  18. void init() {
  19. memset(head, , sizeof(head));
  20. ecnt = ;
  21. }
  22.  
  23. void add_edge(int u, int v, int c, int w) {
  24. to[ecnt] = v; flow[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
  25. to[ecnt] = u; flow[ecnt] = ; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++;
  26. //printf("%d %d %d %d\n", u, v, c, w);
  27. }
  28.  
  29. void spfa() {
  30. for(int i = ; i <= n; ++i) dis[i] = INF;
  31. priority_queue<pair<int, int> > que;
  32. dis[st] = ; que.push(make_pair(, st));
  33. while(!que.empty()) {
  34. int u = que.top().second, d = -que.top().first; que.pop();
  35. if(d != dis[u]) continue;
  36. for(int p = head[u]; p; p = next[p]) {
  37. int &v = to[p];
  38. if(flow[p] && dis[v] > d + cost[p]) {
  39. dis[v] = d + cost[p];
  40. que.push(make_pair(-dis[v], v));
  41. }
  42. }
  43. }
  44. int t = dis[ed];
  45. for(int i = ; i <= n; ++i) dis[i] = t - dis[i];
  46. }
  47.  
  48. int minCost, maxFlow;
  49. bool vis[MAXV];
  50.  
  51. int add_flow(int u, int aug) {
  52. if(u == ed) {
  53. maxFlow += aug;
  54. minCost += dis[st] * aug;
  55. return aug;
  56. }
  57. vis[u] = true;
  58. int now = aug;
  59. for(int p = head[u]; p; p = next[p]) {
  60. int &v = to[p];
  61. if(flow[p] && !vis[v] && dis[u] == dis[v] + cost[p]) {
  62. int t = add_flow(v, min(now, flow[p]));
  63. flow[p] -= t;
  64. flow[p ^ ] += t;
  65. now -= t;
  66. if(!now) break;
  67. }
  68. }
  69. return aug - now;
  70. }
  71.  
  72. bool modify_label() {
  73. int d = INF;
  74. for(int u = ; u <= n; ++u) if(vis[u]) {
  75. for(int p = head[u]; p; p = next[p]) {
  76. int &v = to[p];
  77. if(flow[p] && !vis[v]) d = min(d, dis[v] + cost[p] - dis[u]);
  78. }
  79. }
  80. if(d == INF) return false;
  81. for(int i = ; i <= n; ++i) if(vis[i]) dis[i] += d;
  82. return true;
  83. }
  84.  
  85. int min_cost_flow(int ss, int tt, int nn) {
  86. st = ss, ed = tt, n = nn;
  87. minCost = maxFlow = ;
  88. spfa();
  89. while(true) {
  90. while(true) {
  91. for(int i = ; i <= n; ++i) vis[i] = false;
  92. if(!add_flow(st, INF)) break;
  93. }
  94. if(!modify_label()) break;
  95. }
  96. return minCost;
  97. }
  98. } G;
  99.  
  100. int n, m;
  101. int mat[MAXN][MAXN], ans[MAXN][MAXN];
  102.  
  103. inline int encode(int i, int j) {
  104. if(i > j) swap(i, j);
  105. return i * n + j;
  106. }
  107.  
  108. int main() {
  109. scanf("%d", &n);
  110. for(int i = ; i <= n; ++i) for(int j = ; j <= n; ++j) scanf("%d", &mat[i][j]);
  111. m = n * n;
  112. int ss = n + m + , tt = ss + ;
  113. G.init();
  114. int sum = n * (n - ) * (n - ) / ;
  115. for(int i = ; i <= n; ++i) {
  116. for(int j = , tmp = ; j < n; ++j, tmp += ) G.add_edge(ss, i, , tmp);
  117. for(int j = ; j <= n; ++j) if(mat[i][j] != )
  118. ans[i][j] = G.ecnt, G.add_edge(i, encode(i, j), , );
  119. }
  120. for(int i = ; i <= m; ++i) G.add_edge(i + n, tt, , );
  121. int x = G.min_cost_flow(ss, tt, tt);
  122. printf("%d\n", sum - (x - n * (n - ) / ) / );
  123. for(int i = ; i <= n; ++i) {
  124. for(int j = ; j <= n; ++j) {
  125. if(j != ) printf(" ");
  126. if(mat[i][j] != ) printf("%d", mat[i][j]);
  127. else {
  128. if(G.flow[ans[i][j]] == ) printf("");
  129. else printf("");
  130. }
  131. }
  132. puts("");
  133. }
  134. }

BZOJ 2597 剪刀石头布(最小费用最大流)(WC2007)的更多相关文章

  1. bzoj 2597 剪刀石头布 —— 拆边费用流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 不合法的三个人之间的关系就是一个人赢了两次: 记 \( deg[i] \) 表示第 \ ...

  2. 【BZOJ-2597】剪刀石头布 最小费用最大流

    2597: [Wc2007]剪刀石头布 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1016  Solved:  ...

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

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

  4. BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流

    传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...

  5. BZOJ 3876 [AHOI/JSOI2014]支线剧情 (最小费用可行流)

    题面:洛谷传送门 BZOJ传送门 题目大意:给你一张有向无环图,边有边权,让我们用任意条从1号点开始的路径覆盖这张图,需要保证覆盖完成后图内所有边都被覆盖至少一次,求覆盖路径总长度的最小值 最小费用可 ...

  6. 【BZOJ】1221: [HNOI2001] 软件开发(最小费用最大流)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1221 先吐槽一下,数组依旧开小了RE:在spfa中用了memset和<queue>的版本 ...

  7. BZOJ 1927 星际竞速(最小费用最大流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1927 题意:一个图,n个点.对于给出的每条边 u,v,w,表示u和v中编号小的那个到编号 ...

  8. BZOJ 1061 志愿者招募(最小费用最大流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1061 题意:申奥成功后,布布经过不懈努力,终于 成为奥组委下属公司人力资源部门的主管.布 ...

  9. bzoj 1877 [SDOI2009]晨跑(最小费用最大流)

    Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十 ...

  10. bzoj 1927 [Sdoi2010]星际竞速(最小费用最大流)

    1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1576  Solved: 954[Submit][Statu ...

随机推荐

  1. ProjectServer如何创建时间表

    默认配置的ProjectServer是没有时间表的,任务汇报的时候不能汇报工时,只能汇报任务的百分比. 但如果有企业一定要用工时来汇报的话,我们就需要开启时间表. 点击服务器设置-->时间报告阶 ...

  2. BionicApi 学习笔记

    1.内存管理 malloc, realloc, free new, delete2.文件输入操作 fopen, fwrite, fputs, fputc, fprintf, fflush fread, ...

  3. vi常用命令学习

    (1)移动光标 h : 左移光标l : 右移光标j : 下移光标k : 上移光标 w : 移动到下一个单词词头b : 移动到上一个单词词头e : 移动到本单词的尾部 0 :移动到当前行的开端$ :移动 ...

  4. js替换字符串中的空格,换行符\r\n或\n替换成<br>

    为了让回车换行符正确显示,需要将 \n 或 \r\n 替换成 <br>.同样地,将空格替换存  .这里我们通过正则表达式来替换. 一.替换所有的空格.回车换行符 //原始字符串 var s ...

  5. 洛谷P2052 [NOI2011]道路修建(树形DP)

    题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路. 每条道 ...

  6. EF core 中用lambda表达式和Linq的一些区别

    转眼一看,又过了10几天没有写博客了,主要还是没有什么可以写的,因为遇到的问题都不是很有价值.不过最近发现用lambda表达式,比用Linq的代码量会少一些,而且也方便一些.不过两者都差不多,相差不是 ...

  7. 前端之Vue.js库的使用

    vue.js简介 Vue.js读音 /vjuː/, 类似于 view Vue.js是前端三大新框架:Angular.js.React.js.Vue.js之一,Vue.js目前的使用和关注程度在三大框架 ...

  8. centos7-mongodb3.4.6集群的搭建

    0.需要环境 安装包:mongodb-linux-x86_64-3.4.6.tgz 安装路径:/usr/mongodb 服务器: 192.168.177.131/132/133 mongos 2000 ...

  9. Chrome Google 快捷键

    窗口和标签页快捷方式 Ctrl+N 打开新窗口 按住 Ctrl‎ 键,然后点击链接 在新标签页中打开链接 按住 Shift 键,然后点击链接 在新窗口中打开链接 Alt+F4 关闭当前窗口 Ctrl+ ...

  10. Laravel 5.5搭建(lunix-ubuntu)

    基本配置 PHP >= 7.0.0 PHP OpenSSL 扩展 PHP PDO 扩展 PHP Tokenizer 扩展 PHP XML 扩展 1:nginx sudo apt-get upda ...