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。输出矩阵要保证合法,不能发生矛盾。
题解:http://blog.csdn.net/pouy94/article/details/5972444
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 = 110;
  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, 0, sizeof(head));
 20         ecnt = 2;
 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] = 0; 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 = 1; i <= n; ++i) dis[i] = INF;
 31         priority_queue<pair<int, int> > que;
 32         dis[st] = 0; que.push(make_pair(0, 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 = 1; 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 ^ 1] += 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 = 1; 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 = 1; 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 = 0;
 88         spfa();
 89         while(true) {
 90             while(true) {
 91                 for(int i = 1; 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 = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) scanf("%d", &mat[i][j]);
111     m = n * n;
112     int ss = n + m + 1, tt = ss + 1;
113     G.init();
114     int sum = n * (n - 1) * (n - 2) / 6;
115     for(int i = 1; i <= n; ++i) {
116         for(int j = 1, tmp = 1; j < n; ++j, tmp += 2) G.add_edge(ss, i, 1, tmp);
117         for(int j = 1; j <= n; ++j) if(mat[i][j] != 0)
118             ans[i][j] = G.ecnt, G.add_edge(i, encode(i, j), 1, 0);
119     }
120     for(int i = 1; i <= m; ++i) G.add_edge(i + n, tt, 1, 0);
121     int x = G.min_cost_flow(ss, tt, tt);
122     printf("%d\n", sum - (x - n * (n - 1) / 2) / 2);
123     for(int i = 1; i <= n; ++i) {
124         for(int j = 1; j <= n; ++j) {
125             if(j != 1) printf(" ");
126             if(mat[i][j] != 2) printf("%d", mat[i][j]);
127             else {
128                 if(G.flow[ans[i][j]] == 0) printf("1");
129                 else printf("0");
130             }
131         }
132         puts("");
133     }
134 }

View Code

转载于:https://www.cnblogs.com/oyking/p/3330462.html

BZOJ 2597 剪刀石头布(最小费用最大流)(WC2007)相关推荐

  1. bzoj 1834: [ZJOI2010]network 网络扩容【最大流+最小费用最大流】

    第一问直接跑最大流即可.建图的时候按照费用流建,费用为0. 对于第二问,在第一问dinic剩下的残量网络上建图,对原图的每条边(i,j),建(i,j,inf,cij),表示可以用c的花费增广这条路.然 ...

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

    不知道为什么这么慢.... 费用流,拆点.... --------------------------------------------------------------------------- ...

  3. bzoj 2245 [SDOI2011]工作安排【最小费用最大流】

    其实不用拆点,对于每个人我们假装他是\( s[i]+1 \)个点,可以由他向T点分别连\( s[i]+1 \)条边,容量为\( t[i][j]-t[i][j-1]\),由S点向所有产品i连容量为c[i ...

  4. bzoj 1070: [SCOI2007]修车【最小费用最大流】

    一开始从客人角度想的,怎么建都不对 从一个修车工所接待的所有顾客花费的总时间来看,设一共有x个人,那么第一个修的对总时间的贡献是x*w1,第二个是(x-1)*w2-以此类推.所以把第i个修车工拆成n组 ...

  5. 有下界的最小费用可行流2.0(bzoj 3876: [Ahoi2014]支线剧情)

    什么是有下界的最小费用可行流? 平时来讲都是最小费用最大流,也就是在满流的前提条件下费用尽可能的少,而最小费用可行流一般不要求满流,但是每条边都有最小流量要求(比如经过边e(u,v)的流量不能少于4等 ...

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

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

  7. 有上下限的最小费用可行流

    例题 BZOJ 3876 题意,有N个点,并且有一些边,每个点必须要经过一次,但是不限经过次数,也就是有下界的情况,且下界为1,现在每次的起点都是1,问至少花费的代价,使得每次从1开始,终点不限的情况 ...

  8. 乌鲁木齐网络赛J题(最小费用最大流模板)

    ACM ICPC 乌鲁木齐网络赛 J. Our Journey of Dalian Ends 2017-09-09 17:24 243人阅读 评论(0) 收藏 举报  分类: 网络流(33)  版权声 ...

  9. POJ - 2516 Minimum Cost 最小费用最大流

    题目链接 题意:给n,m,k表示商店数,储存店数,种类数 然后给n*k表示每个水果店需求每种种类的数量: 表示成 need[i][j] 再给m*k表示每个储存店每种种类数量: 表示成store[i][ ...

  10. pku The Windy's KM最小权匹配 or 最小费用最大流

    http://poj.org/problem?id=3686 题意: 给定n个玩具,有m个车间,给出每个玩具在每个车间的加工所需的时间mat[i][j]表示第i个玩具在第j个车间加工所需的时间,规顶只 ...

最新文章

  1. SAP PM入门系列28 - IW67 Display Tasks
  2. Oracle 用户概念与基本操作
  3. Http协议中的Content-Length属性
  4. spark面试总结1
  5. UE选择合适的小区进行驻留以后
  6. JavaScript的Prototype实现
  7. Intellj(IDEA) warning no artifacts configured
  8. [CF1082E] Increasing Frequency
  9. 抖音城市美食算数报告
  10. HR怼程序员频繁跳槽,程序员竟这么回怼
  11. 进云仿美团外卖平台 v1.39源码
  12. 对象交互 模拟顾客点菜 c# 1614008435
  13. 如何选择RabbitMQ和Kafka
  14. mysql 存储过程实际应用,mysql 存储过程应用实例
  15. 图:出场顺序号码随机抽取及公开展示,并行随机抽取多个题目号码及公开展示-软件原型设计
  16. Windows+WSL+DockerDesktop下安装OpenV2X
  17. 面试阿里,看这一篇就够了!
  18. springboot中设置pageSize的默认值
  19. Python字典知识总结
  20. 谷歌经典bert模型从下载源码到运行成功

热门文章

  1. java 微信 回复_微信java 开发2 发送文本消息并回复
  2. 蓝桥杯单片机stc15f2k61s2矩阵按键中断扫描代码
  3. Java 基础知识总结(下)-王者笔记《收藏版》
  4. 服务禁止方法_Linux禁止ping以及开启ping的方法
  5. 怎样把文件传到华为云服务器,如何把文件传到云服务器上
  6. C++ 重载强制类型转换运算符
  7. Java try catch finally语句
  8. css的属性是变量是怎么表达,CSS自定义变量属性——像less,sass那样在css中使用变量(译)...
  9. iOS开发里面的4个层次
  10. 计算机科学和软件工程区别,计算机科学和软件工程的区别