【二分图染色】AtCoder CODE FESTIVAL 2017(qual B)C[3 Steps]题解

来源:互联网 发布:unity3d素材免费资源 编辑:程序博客网 时间:2024/05/18 19:44

题目概述

给出 n 个点, m 条无向边(保证没有自环和重边,且图联通)。如果两个点之间存在长度为 3 的边,就添加一条边(之后也可以走这条边)。求最多加多少边。

解题报告

和YZ哥哥一起打AtCoder……被切了C的YZ哥哥虐翻……

首先我们会发现如果有一组满足的点对 (u,v) ,不管添加了多少新边,这组点对将依然满足。也就是说,只要执行能加就加的策略,答案就是固定的。

那么我们可以得出重要结论:初始图中距离为奇数的点对 (u,v) 在最终图中一定有边。这样的话问题简化为:求最终图中的边数 M ,答案就是 Mm

接着就会发现距离为奇数这个性质和二分图奇环很有联系,于是:

  1. 原图是二分图:走奇数步不会成环,也就是说左 LR 都有边相连,即最终图的边数是 L×R
  2. 原图不是二分图:走奇数步会成环,也就是说所有点都会相连,即最终图的边数是 n×(n1)÷2

示例程序

#include<cstdio>#include<cstring>#include<cstdlib>using namespace std;typedef long long LL;const int maxn=100000,maxm=100000;int n,m,col[maxn+5],A,B;int E,lnk[maxn+5],son[maxm*2+5],nxt[maxm*2+5];inline void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}void Dfs(int x,int now=0,int fa=0){    col[x]=now;now^=1;    for (int j=lnk[x];j;j=nxt[j])    {        if (col[son[j]]==-1) Dfs(son[j],now,x);        if (col[son[j]]!=now) printf("%lld\n",(LL)n*(n-1)/2-m),exit(0);    }}int main(){    freopen("C.in","r",stdin);    freopen("C.out","w",stdout);    scanf("%d%d",&n,&m);memset(col,255,sizeof(col));    for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),Add(x,y),Add(y,x);    Dfs(1);for (int i=1;i<=n;i++) if (col[i]) A++; else B++;    return printf("%lld\n",(LL)A*B-m),0;}
原创粉丝点击