Luogu P4249 [WC2007]剪刀石头布

Link

先把题意抽象一下:给定一个存在一部分为定向的边的竞赛图,最大化它的三元环个数。

我们知道竞赛图的三元环个数为\({n\choose 3}-\sum\limits_{i=1}^n{deg_i\choose 2}\)。

对于一条未定向的边\((u,v)\),它会使\(u,v\)其中一个点的度数加一。

对于一个点而言,随着度数的增加,度数加一使得三元环减少的个数也是在增加的,也就是说这是一个凸函数。

那么直接费用流就行了,建图就是凸函数差分的那一套方法。

#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
const int N=107,V=6007,E=50007,inf=1e9;
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int s,t,tot=1,a[N][N],deg[N],head[V],ver[E],next[E],edge[E],cost[E],dis[V],flow[V],inq[V],id[V];std::queue<int>q;struct node{int u,v,id;}p[N*N];
void add(int u,int v,int f,int c)
{
    ver[++tot]=v,next[tot]=head[u],head[u]=tot,edge[tot]=f,cost[tot]=c;
    ver[++tot]=u,next[tot]=head[v],head[v]=tot,edge[tot]=0,cost[tot]=-c;
}
int spfa()
{
    memset(dis+1,0x3f,t<<2),q.push(s),inq[s]=1,flow[s]=inf,dis[s]=0,id[t]=-1;
    for(int i,u,v;!q.empty();)
	for(i=head[u=q.front()],q.pop(),inq[u]=0;i;i=next[i])
	    if(edge[i]&&dis[v=ver[i]]>dis[u]+cost[i])
		if(dis[v]=dis[u]+cost[i],id[v]=i,flow[v]=std::min(flow[u],edge[i]),!inq[v])
		    q.push(v),inq[v]=1;
    return ~id[t];
}
int EK()
{
    int mincost=0;
    for(int p;spfa();) for(mincost+=flow[t]*dis[t],p=t;p^s;p=ver[id[p]^1]) edge[id[p]]-=flow[t],edge[id[p]^1]+=flow[t];
    return mincost;
}
int main()
{
    int n=read(),ans=n*(n-1)*(n-2)/6,cnt=n;s=n*(n+1)/2+1,t=s+1;
    for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=read();
    for(int i=1;i<n;++i) for(int j=i+1;j<=n;++j) if(!a[i][j]) ++deg[j]; else if(a[i][j]==1) ++deg[i]; else add(s,++cnt,1,0),add(cnt,j,1,0),add(cnt,i,1,0),p[cnt]={i,j,tot};
    for(int i=1;i<=n;++i) for(int j=deg[i];j<n;++j) add(i,t,1,j);
    for(int i=1;i<=n;++i) ans-=deg[i]*(deg[i]-1)/2;
    printf("%d\n",ans-EK());
    for(int i=n+1;i<=cnt;++i) a[p[i].v][p[i].u]=!(a[p[i].u][p[i].v]=edge[p[i].id]);
    for(int i=1;i<=n;++i,puts("")) for(int j=1;j<=n;++j) printf("%d ",a[i][j]);
}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12657707.html

时间: 2024-10-09 22:07:21

Luogu P4249 [WC2007]剪刀石头布的相关文章

【BZOJ 2597】 [Wc2007]剪刀石头布

2597: [Wc2007]剪刀石头布 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge Submit: 492  Solved: 227 [Submit][Status] Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道于统计有多少这样的剪刀石头布情况发生,即有多少对无序三元组

[Wc2007]剪刀石头布

[Wc2007]剪刀石头布 http://www.lydsy.com/JudgeOnline/problem.php?id=2597 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道于统计有多少这样的剪刀石头布情况发生,即有多少对

2597: [Wc2007]剪刀石头布

2597: [Wc2007]剪刀石头布 链接 分析: 费用流. 首先转化一下问题,整张图最优的情况是存在$C_n^3$个,即任意3个都行,然后考虑去掉最少不满足的三元环. 如果u赢了v,u向v连一条边,如果v有k条入边,那么说明少了$C_k^2$个三元环,所对每场比赛分配度数,求最小费用最大流. 具体地:S向每场比赛连容量为1,花费为0的边:每场比赛向两个人连容量为1,花费为0的边:每个人因为度数不同,花费不同,所以差分后建边. 代码: #include<cstdio> #include<

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^

BZOJ2597 [Wc2007]剪刀石头布

什么鬼...冬令营题目不看题解能做? (看了题解也不会2333) 其中有一部还是可以仔细思考一下的,就是对于费用流,如果每条边边满足:cost = a * flow2,如何做? 我们可以拆边,新边上,每条边流量为1,费用为a * (x2 - (x - 1)2)(就是费用为a * (12 - 02), a * (22 - 12)...) 拆边的思想还是很广泛的,恩...! 1 /************************************************************

BZOJ 2597 WC2007 剪刀石头布 费用流

题目大意:给出一张竞赛图中的其中几条单向边,剩下的边随意定向.问最多可以形成多少三元环. 思路:对于任意三个点来说,他们组成了三元环,当且仅当这些点的入度=处度 = 1.如果没有组成三元环,只需要改变这其中任意一条边的方向,使得一个点的入度变成2,一个点的出度变成2.我们只需要算出有多少三个点中有一个点的入度为2的就可以了,并最小化这个东西. 通过公式:ans=C(n,3)-ΣC(degree[x],2)可以发现,我们只需要让每个点的入度尽可能小.由此想到费用流模型(我怎么想不到..) 类似于x

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什

题解#3

感觉自己弱得没救了...求神犇解救T_T 1 2597: [Wc2007]剪刀石头布 补集转化之后就是费用流了.我比较逗方案WA了两发. 1 int n,m,k,mincost,tot=1,cnt,s,t,win[maxn],a[maxn][maxn],b[maxn][maxn],head[maxm],d[maxm],from[2*maxm]; 2 3 bool v[maxm]; 4 5 queue<int>q; 6 7 struct edge{int from,go,next,v,c;}e[

【BZOJ2597】【Wc2007】剪刀石头布 费用流,没写zkw卡时过

题解,比较常规式是费用流,没写那个神贪心. 首先是三元环需要取补集,先C(n,3)算出总环数,然后减去失败的三元环. 我们发现在一个三元环中,如果有某个选手入度(or 出度)为2,那么就会破坏这个环. 所以当选手有x个度时,就会破坏∑(i∈[0,x])个三元环(0+....+x-1),P.S.这个是C(x,2)推出来的. 建图: 第一层源点 到下一层每个点若干条边 条数: 那个选手可能赢的次数, 费用: 第i条边费用i-1, 流量: 1 第二层选手 到可能赢的每个对应竞赛建边 条数: 1 费用: