[WC2007]剪刀石头布(最大流)
一句话题意:给定一张图,每两点之间有一条有向边或无向边,把所有无向边定向,使图中三元环个数尽量多
因为原图是一个完全图,假设图中任意三点都能构成三元环,那么途中三元环的个数为:\(\binom{n}{3}\)。
那么如果一个三元组不是三元环,那么有一个点的出度为2。
我们假设一个点的出度为d,那么对于这个点,三元环会减少\(\frac{d (d-1)}{2}\)
所以三元环的数量为:\(\binom{n}{3}- \sum_{i=1}^n\binom{d[i]}{2}=\binom{n}{3}- \sum_{i=1}^n\frac{d[i] (d[i]-1)}{2}\)
所以我们要最小化:$ \sum_{i=1}^n\frac{d[i] (d[i]-1)}{2}$的值。
怎么做呢?
如果我们对于一条无向边,可能让u出度+1,也可能让v出度+1,非黑即白,所以我们可以考虑费用流。
观察柿子\(\frac{d[i] (d[i]-1)}{2}\),容(hen)易(nan)想到小学等差数列求和公式,于是我们可以将一个点的贡献看成\((0+1+2+3+……+d[i]-1)\)
把每一条边看成一个点,从源点向每条边连一条容量为1,费用为0的边。
对于一条无向边,往u,v分别建一条容量为1,费用为0的边。
有向边则把边和v建一条容量为1,费用为0的边。
每个点向汇点连n条容量为1,费用为0-(n-1)递增的边,表示上面的等差数列(可以表示出任何出度的情况)
最后就是费用流的板子了
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define inf 123456789
#define debug printf("Now is Line : %d\n",__LINE__)
il int read()
{
re int x=0,f=1; re char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return x*f;
}
#define maxn 105
#define maxm 105*105
struct edge
{
int v,w,val,next;
}e[maxm<<3];
int n,a[maxn][maxn],S,T,maxflow,cost,vis[maxm],dis[maxm],head[maxm],cnt=1,pa;
il void add(int u,int v,int val,int w)
{
e[++cnt]=(edge){v,w,val,head[u]};
head[u]=cnt;
e[++cnt]=(edge){u,-w,0,head[v]};
head[v]=cnt;
}
queue<int>q;
il bool spfa()
{
memset(vis,0,sizeof(vis));
memset(dis,127,sizeof(dis));
dis[S]=0; q.push(S);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(re int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w&&e[i].val>0)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[T]!=2139062143;
}
il int dfs(int u,int mi)
{
if(u==T)
{
vis[T]=1;
return mi;
}
vis[u]=1;
int use=0;
for(re int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if((!vis[v]||v==T)&&e[i].val>0&&dis[v]==dis[u]+e[i].w)
{
int low=dfs(v,min(mi-use,e[i].val));
if(low>0)
{
cost+=low*e[i].w;
e[i].val-=low; e[i^1].val+=low;
use+=low;
}
}
}
return use;
}
il void dinic()
{
while(spfa())
{
vis[T]=1;
while(vis[T])
{
memset(vis,0,sizeof(vis));
dfs(S,inf);
}
}
int ans=((n-1)*(n-2)*n)/6;
ans-=cost;
printf("%d\n",ans);
}
int main()
{
n=read(); T=n*n+n+1;
for(re int i=1;i<=n;++i)
{
for(re int j=1;j<=n;++j)
{
a[i][j]=read();
if(i>=j) continue;
if(a[i][j]==2)
{
add(S,(i-1)*n+j,1,0);
add((i-1)*n+j,n*n+i,1,0);
add((i-1)*n+j,n*n+j,1,0);
}
else if(a[i][j]==1) add(S,n*n+j,1,0);
else add(S,n*n+i,1,0);
}
}
for(re int i=1;i<=n;++i)
{
for(re int j=0;j<n;++j) add(n*n+i,T,1,j);
}
dinic();
for(re int i=1;i<=n;++i)
{
for(re int j=i+1;j<=n;++j)
{
if(a[i][j]<2) continue;
for(re int k=head[(i-1)*n+j];k;k=e[k].next)
{
if(e[k].v&&e[k].val==0)
{
a[i][j]=(e[k].v-n*n==j);
a[j][i]=a[i][j]^1;
}
}
}
}
for(re int i=1;i<=n;++i,puts(""))
{
for(re int j=1;j<=n;++j) printf("%d ",a[i][j]);
}
return 0;
}
[WC2007]剪刀石头布(最大流)的更多相关文章
- BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)
BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...
- bzoj 2597 [Wc2007]剪刀石头布——费用流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 三个人之间的关系,除了“剪刀石头布”,就是有一个人赢了2局:所以考虑算补集,则每个人对 ...
- [WC2007]剪刀石头布——费用流
比较有思维含量的一道题 题意:给混合完全图定向(定向为竞赛图)使得有最多的三元环 三元环条件要求比较高,还不容易分开处理. 正难则反 考虑,什么情况下,三元组不是三元环 一定是一个点有2个入度,一个点 ...
- BZOJ 2597: [Wc2007]剪刀石头布(费用流)
传送门 解题思路 考虑全集-不能构成三元环的个数.如果三个点不能构成三元环,一定有一个点的入度为\(2\),继续扩展,如果一个点的度数为\(3\),则会失去3个三元环.对于一个点来说,它所产生的不能构 ...
- [bzoj2597][Wc2007]剪刀石头布_费用流
[Wc2007]剪刀石头布 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 题解: 发现直接求三元环不好求,我们考虑任选三个点不是 ...
- 2597: [Wc2007]剪刀石头布
2597: [Wc2007]剪刀石头布 链接 分析: 费用流. 首先转化一下问题,整张图最优的情况是存在$C_n^3$个,即任意3个都行,然后考虑去掉最少不满足的三元环. 如果u赢了v,u向v连一条边 ...
- [Wc2007]剪刀石头布
[Wc2007]剪刀石头布 http://www.lydsy.com/JudgeOnline/problem.php?id=2597 Time Limit: 20 Sec Memory Limit: ...
- 【BZOJ2597】[Wc2007]剪刀石头布 最小费用流
[BZOJ2597][Wc2007]剪刀石头布 Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之 ...
- [Wc2007]剪刀石头布[补集转化+拆边]
2597: [Wc2007]剪刀石头布 Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1157 Solved: ...
- BZOJ2597 [Wc2007]剪刀石头布(最小费用最大流)
题目大概是说n个人两两进行比赛,问如何安排几场比赛的输赢使得A胜B,B胜C,C胜A这种剪刀石头布的三元组最多. 这题好神. 首先,三元组总共有$C_n^3$个 然后考虑最小化不满足剪刀石头布条件的三元 ...
随机推荐
- 测者的测试技术笔记:揭开java method的一个秘密--巨型函数
相信,很多人都不知道Java的Method的上限为64K.本文将超过这个上限的函数叫做巨型函数. 巨型函数的问题 1.如果代码超过了这个限制,Java编译器就报"Code too large ...
- PJSUA2开发文档--第九章 PJSUA2应用程序示例
9. PJSUA2示例应用程序 9.1 示例应用程序 9.1.1 C++ pjsip-apps/src/samples/pjsua2_demo.cpp 是一个非常简单可用的C++示例应用程序. /* ...
- 关于MongoDB 固定集合(capped collection)的知识梳理
一 . 什么是固定集合 MongoDB中有一种特殊类型的集合,值得我们特别留意,那就是固定集合(capped collection). 固定集合可以声明collection的容量大小,其行为类似于循环 ...
- 微信小程序发红包
背景: 近期一个朋友公司要做活动,活动放在小程序上.小程序开发倒是不难,不过要使用小程序给微信用户发红包,这个就有点麻烦 确定模式: 小程序目前没有发红包接口,要实现的话,只能是模拟红包,即小程序上做 ...
- 利用ZYNQ SOC快速打开算法验证通路(3)——PS端DMA缓存数据到PS端DDR
上篇该系列博文中讲述W5500接收到上位机传输的数据,此后需要将数据缓存起来.当数据量较大或者其他数据带宽较高的情况下,片上缓存(OCM)已无法满足需求,这时需要将大量数据保存在外挂的DDR SDRA ...
- Python 位操作运算符
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100 | 按位或运算符:只要对应的二 ...
- 慢日志查询python flask sqlalchemy慢日志记录
engine = create_engine(ProdConfig.SQLALCHEMY_DATABASE_URI, echo=True) app = Flask(__name__) app.conf ...
- redis 初步认识三(设置登录密码)
1.cmd 2.cd C:\Program Files\Redis 3.redis-cli.exe -h 127.0.0.1 -a 123456
- 使用CompletableFuture优化你的代码执行效率
这篇文章详细讲解java8中CompletableFuture的特性,方法以及实例. 在java8以前,我们使用java的多线程编程,一般是通过Runnable中的run方法来完成,这种方式,有个很明 ...
- Cesium如何通过addImageryProvider方法加载SkylineGlobe Server发布的WMS服务
某某某单位用SkylineGlobeServer7版本发布了好些服务,然后让我们在Cesium里都加载进来展示. 其实只要符合OGC标准的,加进来还是很容易的. 示例代码如下: function te ...