比较有思维含量的一道题

题意:给混合完全图定向(定向为竞赛图)使得有最多的三元环

三元环条件要求比较高,还不容易分开处理。

正难则反

考虑,什么情况下,三元组不是三元环

一定是一个点有2个入度,一个点有2个出度,另一个点一个入度,一个出度

也就是说,每存在一个>=2入度的点,那么会减少一些三元环

进而考虑,如果一个点有d个入度,那么减少的三元环其实是:C(d,2),即,包括它自己,再包括任意两个指向它的点(这里,a指向b,代表a能赢b),构成的三元组都不是三元环

考虑每个点作为某些个非法三元组的话,那么,

总共的三元环是:C(n,3)-∑C(du[i],2)

C(du[i],2)统计了所有与i有关的非法三元组,所以不重不漏统计完了。

怎样最小化这个∑?

定向,就是某些点的入度增加的过程。所以考虑某个点增加一个入度,减少的三元环的数量是多少。

即C(d+1,2)-C(d,2)=d即减少原来度数的三元环

这个减少是逐一增加的,n*(n-1)/2是下凸函数,可以考虑拆边费用流。

这个题的具体做法是:

把每个要定向的边看做一个点,从S到这个点连(1,0),意义是只能确定一个方向

这个点向所代表的边的两个原图端点连(1,0)的边,意义是增加入度,且只能给一个增加

每个原图 节点向T连(1,d),(1,d+1)...(1,d+n-2)的边,意义是,每增加一个入度,就会增加d的代价

最小费用最大流,spfa恰好先选择d,再选择d+1,,,,刚好符合实际的代价

最大流之后,每个边都定向完毕,而且增加的代价也都是对的。

至于输出方案,找每个边的代表点,看其哪一侧流量是0,就是哪一侧输。

代码:

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=;
const int inf=0x3f3f3f3f;
int n,s,m,t;
struct node{
int nxt,to,w,v;
}e[*(N*N+N*N*+N*N)];
int hd[N+N*N],cnt=;
void add(int x,int y,int w,int v){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
e[cnt].v=v;
e[cnt].w=w;
hd[x]=cnt; e[++cnt].nxt=hd[y];
e[cnt].to=x;
e[cnt].w=;
e[cnt].v=-v;
hd[y]=cnt;
}
int mp[N][N];
int op[N][N];
queue<int>q;
bool vis[N+N*N];
int dis[N*N+N];
int incf[N*N+N],pre[N*N+N];
bool spfa(){
while(!q.empty()) q.pop();
memset(dis,inf,sizeof dis);
dis[s]=;
q.push(s);
pre[s]=;
incf[s]=inf;
while(!q.empty()){
int x=q.front();q.pop();
vis[x]=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(e[i].w){
if(dis[y]>dis[x]+e[i].v){
dis[y]=dis[x]+e[i].v;
pre[y]=i;
incf[y]=min(incf[x],e[i].w);
if(!vis[y]){
vis[y]=;
q.push(y);
}
}
}
}
}
if(dis[t]==inf) return false;
return true;
}
int cos,maxflow;
int du[N];
void upda(){
int x=t;
while(pre[x]){
e[pre[x]].w-=incf[t];
e[pre[x]^].w+=incf[t];
x=e[pre[x]^].to;
}
cos+=incf[t]*dis[t];
maxflow+=incf[t];
}
int num(int i,int j){
return n+(i-)*(n-)+j;
}
int main(){
rd(n);
s=,t=n+n*n+;
for(reg i=;i<=n;++i){
for(reg j=;j<=n;++j){
rd(mp[i][j]);
if(mp[i][j]==&&i<j){
add(s,num(i,j),,);
add(num(i,j),i,,);
add(num(i,j),j,,);
}else if(mp[i][j]==){
du[j]++;
}
}
}
int ans=n*(n-)*(n-)/; for(reg i=;i<=n;++i){
ans-=du[i]*(du[i]-)/;
for(reg j=du[i];j<=n-;++j){
add(i,t,,j);
}
}
while(spfa()) upda();
ans-=cos;
printf("%d\n",ans);
memcpy(op,mp,sizeof mp);
for(reg i=;i<=n;++i){
for(reg j=;j<=n;++j){
if(mp[i][j]==&&i<j){
int x=num(i,j);
for(reg p=hd[x];p;p=e[p].nxt){
int y=e[p].to;
if(y!=s&&e[p].w==){
if(y==j){
op[i][j]=;
op[j][i]=;
}else{
op[i][j]=;
op[j][i]=;
}
}
}
}
}
}
for(reg i=;i<=n;++i){
for(reg j=;j<=n;++j){
printf("%d ",op[i][j]);
}puts("");
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/12/15 11:01:16
*/

总结:

值得学习的是:

1.正难则反,考虑非法的三元组,这样可以通过度数直接分开计算

2.边点转化,对无向图定向、而且贡献和点的入度有关,可以尝试采取这种策略。

3.下凸函数拆边费用流。因为下凸函数,所以最小费用的时候,每次会先选择最小的,然后往右或者往左选,那么拆边,实际上真正选择的恰好也符合实际情况。

[WC2007]剪刀石头布——费用流的更多相关文章

  1. BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)

    BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...

  2. BZOJ 2597: [Wc2007]剪刀石头布(费用流)

    传送门 解题思路 考虑全集-不能构成三元环的个数.如果三个点不能构成三元环,一定有一个点的入度为\(2\),继续扩展,如果一个点的度数为\(3\),则会失去3个三元环.对于一个点来说,它所产生的不能构 ...

  3. bzoj 2597 [Wc2007]剪刀石头布——费用流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 三个人之间的关系,除了“剪刀石头布”,就是有一个人赢了2局:所以考虑算补集,则每个人对 ...

  4. Luogu4249 WC2007 石头剪刀布 费用流

    传送门 考虑竞赛图三元环计数,设第\(i\)个点的入度为\(d_i\),根据容斥,答案为\(C_n^3 - \sum C_{d_i}^2\) 所以我们需要最小化\(\sum C_{d_i}^2\) 考 ...

  5. [bzoj2597][Wc2007]剪刀石头布_费用流

    [Wc2007]剪刀石头布 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 题解: 发现直接求三元环不好求,我们考虑任选三个点不是 ...

  6. 【bzoj2597】[Wc2007]剪刀石头布 动态加边费用流

    题目描述 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道于统计有多少这 ...

  7. BZOJ2597 [Wc2007]剪刀石头布 【费用流】

    题目链接 BZOJ2597 题解 orz思维差 既然是一张竞赛图,我们选出任意三个点都可能成环 总方案数为 \[{n \choose 3}\] 如果三个点不成环,会发现它们的度数是确定的,入度分别为\ ...

  8. bzoj2597: [Wc2007]剪刀石头布(费用流)

    传送门 不得不说这思路真是太妙了 考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样 就是说一个三元组$(a,b,c)$,其中$a$赢两场,$b$赢一场,$c$没有赢 所以如果第$i$个人赢 ...

  9. bzoj 2597: [Wc2007]剪刀石头布【最小费用最大流】

    脑子不太清楚一个zz问题调了好久-- 首先正难则反,因为三元环好像没什么特点,就考虑让非三元环个数最小 考虑非三元环特点,就是环上一定有一个点的入度为2,联系整张图,三元环个数就是每个点C(入度,2) ...

随机推荐

  1. 函数:引用file类对象及io类对象作为参数打印文本及显示文本

    #include <iostream> #include <fstream> #include <cstdlib> using namespace std; voi ...

  2. 014---Django的中间件

     前戏 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装 ...

  3. python基础集结号

    Python 号称是最接近人工智能的语言,因为它的动态便捷性和灵活的三方扩展,成就了它在人工智能领域的丰碑 走进Python,靠近人工智能 一.编程语言Python的基础 之 "浅入浅出&q ...

  4. 【转】在Ubuntu 16.10 Server 上部署 Moodle

    第一步 安装 Ubuntu 16.10 Server LTS Moodle 的官方文档肯定了Ubuntu Server LTS 是适合运维Moodle平台的. 1.使用纯代码交互的服务器Ubuntu更 ...

  5. 安装Sql Server 2008时出错

           在安装Sql Server 2008的时候,出现一个错误,说是"SQL Server 2005 Express tools"安装了,需要移除,但是我在控制面板里面找了 ...

  6. redis入门:介绍、特点、安装、各类型常用操作

    一.redis介绍 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. Redis支持多种类型的数据结构,如 字符串(strings), 散列(ha ...

  7. 【廖雪峰老师python教程】day1

    主要内容摘要 函数参数[个人感觉难度很大,却很重要,可以先大概记一记]不要用的太复杂.戳这儿温习 递归函数:使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出.重点:找到递归关系和终止条件 ...

  8. 「日常训练」 不容易系列之(3)—— LELE的RPG难题 (HDU 2045)

    题目简述 有排成一行的n" role="presentation">nn个方格,用红(Red).粉(Pink).绿(Green)三色涂每个格子,每格涂一色,要求任何 ...

  9. 在阿里云上遇见更好的Oracle(三)

    鬼扯完“去IOE”,继续回来说说这个系列文章的主角Oracle. 在DB-Engine的数据库排行榜中,Oracle已经占据了多年的第一(最新排名可以点击“阅读原文”).当然因为互联网行业的兴起,My ...

  10. 九度OJ--Q1166

    import java.text.DecimalFormat;import java.util.Scanner; /* * 题目描述: * 立方根的逼近迭代方程是 y(n+1) = y(n)*2/3 ...