BZOJ2597 [Wc2007]剪刀石头布(最小费用最大流)
题目大概是说n个人两两进行比赛,问如何安排几场比赛的输赢使得A胜B,B胜C,C胜A这种剪刀石头布的三元组最多。
这题好神。
- 首先,三元组总共有$C_n^3$个
- 然后考虑最小化不满足剪刀石头布条件的三元组个数,而要求的结果就是总数-这个不满足的个数了:
- 对于三个人构不成剪刀石头布现象,当且仅当,其中一个人赢了其他两个人
- 而由于这是完全图,如果一个人赢了$x_i$场那么包含这个人且这个人赢的次数最多的不满足剪刀石头布现象的三元组就有$C_{x_i}^2$个
- 所以目的就是最小化$\sum C_{x_i}^2$,即$\sum x_i^2-C_n^2$,其中$C_n^2$是常数可以拿开
- 考虑用最小费用最大流求解$\sum x_i^2$的最小值,源点-比赛-人-汇点这样连边:
- 源点到各个比赛的边是容量1费用0
- 比赛到人是容量1费用0的边
- 而人到汇点,根据那个目标式,可知如果流量是$f$,那么费用是$f^2$,解决的方式就是依次连接容量1费用分别是1、3、5、7、9……的边!
- 构图完毕跑最小费用最大流,最多的剪刀石头布现象数就是$C_n^3-(MCMF-C_n^2)$,最后再遍历一下残量网络输出方案即可
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 11111
#define MAXM 111111*4
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int vs,vt,NV,NE,head[MAXN];
void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u; edge[NE].cap=; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
int d[MAXN],pre[MAXN];
bool vis[MAXN];
bool SPFA(){
for(int i=; i<NV; ++i){
d[i]=INF; vis[i]=;
}
d[vs]=; vis[vs]=;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=;
que.push(v);
}
}
}
vis[u]=;
}
return d[vt]!=INF;
}
int MCMF(){
int res=;
while(SPFA()){
int flow=INF,cost=;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int ans[][];
int main(){
int n,a;
scanf("%d",&n);
vs=n*n+n; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
int cost=;
for(int j=; j<=n; ++j){
addEdge(n*n+i,vt,,cost);
cost+=;
}
}
for(int i=; i<n; ++i){
for(int j=; j<n; ++j){
scanf("%d",&a);
if(i>=j) continue;
addEdge(vs,i*n+j,,);
if(a==){
addEdge(i*n+j,n*n+i,,);
}else if(a==){
addEdge(i*n+j,n*n+j,,);
}else{
addEdge(i*n+j,n*n+i,,);
addEdge(i*n+j,n*n+j,,);
}
}
}
printf("%d\n",n*(n-)*(n-)/-(MCMF()-(n-)*n/)/);
for(int x=; x<n; ++x){
for(int y=x+; y<n; ++y){
for(int i=head[x*n+y]; i!=-; i=edge[i].next){
if(i& || edge[i].cap) continue;
if(edge[i].v==x+n*n){
ans[x][y]=; ans[y][x]=;
}else{
ans[x][y]=; ans[y][x]=;
}
}
}
}
for(int i=; i<n; ++i){
for(int j=; j<n; ++j) printf("%d ",ans[i][j]);
putchar('\n');
}
return ;
}
BZOJ2597 [Wc2007]剪刀石头布(最小费用最大流)的更多相关文章
- 【BZOJ-2597】剪刀石头布 最小费用最大流
2597: [Wc2007]剪刀石头布 Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1016 Solved: ...
- bzoj2597: [Wc2007]剪刀石头布(费用流)
传送门 不得不说这思路真是太妙了 考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样 就是说一个三元组$(a,b,c)$,其中$a$赢两场,$b$赢一场,$c$没有赢 所以如果第$i$个人赢 ...
- [bzoj2597][Wc2007]剪刀石头布_费用流
[Wc2007]剪刀石头布 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 题解: 发现直接求三元环不好求,我们考虑任选三个点不是 ...
- BZOJ2597 WC2007剪刀石头布(费用流)
考虑使非剪刀石头布情况尽量少.设第i个人赢了xi场,那么以i作为赢家的非剪刀石头布情况就为xi(xi-1)/2种.那么使Σxi(xi-1)/2尽量小即可. 考虑网络流.将比赛建成一排点,人建成一排点, ...
- BZOJ2597 [Wc2007]剪刀石头布 【费用流】
题目链接 BZOJ2597 题解 orz思维差 既然是一张竞赛图,我们选出任意三个点都可能成环 总方案数为 \[{n \choose 3}\] 如果三个点不成环,会发现它们的度数是确定的,入度分别为\ ...
- [板子]最小费用最大流(Dijkstra增广)
最小费用最大流板子,没有压行.利用重标号让边权非负,用Dijkstra进行增广,在理论和实际上都比SPFA增广快得多.教程略去.转载请随意. #include <cstdio> #incl ...
- bzoj1927最小费用最大流
其实本来打算做最小费用最大流的题目前先来点模板题的,,,结果看到这道题二话不说(之前打太多了)敲了一个dinic,快写完了发现不对 我当时就这表情→ =_=你TM逗我 刚要删突然感觉dinic的模 ...
- ACM/ICPC 之 卡卡的矩阵旅行-最小费用最大流(可做模板)(POJ3422)
将每个点拆分成原点A与伪点B,A->B有两条单向路(邻接表实现时需要建立一条反向的空边,并保证环路费用和为0),一条残留容量为1,费用为本身的负值(便于计算最短路),另一条残留容量+∞,费用为0 ...
- HDU5900 QSC and Master(区间DP + 最小费用最大流)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...
随机推荐
- kmp
#include <bits/stdc++.h> #define MAXN 100000 using namespace std; string a, b; int next[MAXN]; ...
- Android Studio 生成Jar包时遇到的gradlew下载问题
网上介绍说使用gradlew打包jar,可是输入gradlew makeJar后就开始download XXX.zip,但是等了很久都没有完成.解决办法如下: 原文:http://blog.csdn ...
- php提示 Notice: Use of undefined constant name - assumed
我们知道php在数组中写变量有二几种方法,我们出现这种提示就是你写成了[name]这种所以会有Notice: Use of undefined constant name - assumed name ...
- .net学习之委托和事件
1.什么是委托通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器上传图片: 2.委托语法准备一个方法:string Hello(string userName){} string ...
- 基于python网络编程实现支持购物、转账、存取钱、定时计算利息的信用卡系统
一.要求 二.思路 1.购物类buy 接收 信用卡类 的信用卡可用可用余额, 返回消费金额 2.信用卡(ATM)类 接收上次操作后,信用卡可用余额,总欠款,剩余欠款,存款 其中: 1.每种交易类型不单 ...
- loj 1357(树形dp)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1357 #define _CRT_SECURE_NO_WARNINGS #include ...
- 枚举PEB获取进程模块列表
枚举进程模块的方法有很多种,常见的有枚举PEB和内存搜索法,今天,先来看看实现起来最简单的枚举PEB实现获取进程模块列表. 首先,惯例是各种繁琐的结构体定义.需要包含 ntifs.h 和 WinDef ...
- Linux学习笔记(20) Linux系统管理
1.进程管理 进程是正在执行的一个程序或命令,每一个进程都是一个运行的实体,都有自己的地址空间,并占用一定的系统资源. 进程管理的作用有判断服务器健康状态.查看系统中所有进程及杀死进程.一般都可以采用 ...
- 【转】Struts2解决表单重复提交问题
用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此,重复提 ...
- mybatis中foreach的用法(转)
foreach一共有三种类型,分别为List,[](array),Map三种. foreach属性 属性 描述 item 循环体中的具体对象.支持属性的点路径访问,如item.age,item.inf ...