码迷,mamicode.com
首页 > 其他好文 > 详细

模拟赛AT2046 Namori 二分图

时间:2019-03-05 21:33:06      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:否则   read   def   freopen   space   节点   平衡   整数   就是   

题面

Description
? 现在给你一张NN个点MM条边的连通图,我们保证N?1≤M≤NN?1≤M≤N,且无重边和自环。
? 每一个点都有一种颜色,非黑即白。初始时,所有点都是白色的。
? 想通过执行若干次某种操作的方式,来将所有的点变成黑色。操作方式如下:
? 选择一对颜色相同的相邻的节点(存在边直接连接彼此),将它们的颜色反转。即若原来都是白色,则都变成黑色,反之亦然。
? 现在想知道,他能否通过执行这种操作以达到目的。如果可以,他还希望步数尽可能的少。

Input
? 第一行有两个正整数NN和MM(2≤N≤1052≤N≤105,N?1≤M≤NN?1≤M≤N)
接下来MM行,每行2个正整数aa和bb(1≤a,b≤N1≤a,b≤N),表示每条边连接的两个点。

Output
? 如果存在操作方案能达到目的,请输出最少操作次数。
否则,请输出?1

解法

先考虑树

大佬们说这是一个套路:看到对相同颜色的点进行操作,就把他们建成不同颜色。
于是我们就先套路,对树进行分层黑白染色,于是原问题转化为进行多少次操作,可以让整棵树上颜色对调。
如果黑白颜色个数不同显然不行。
考虑一个子树的根,他和他父亲最少要操作子树内黑白颜色的差次,对于每一个节点维护这样一个S_i,
答案的下界就是S_i的绝对值的和,显然这个下界是可以取到的。

奇环

断开一条换上的边,两点是同色的,也就是说可以对这条边进行操作凭空让黑点或白点个数增加(将原来的白点看成白点,黑点看成白点理解即可)
如果此时黑白点个数不平衡,且差为偶数,就可以同过这条边平衡。
先断开这条边,计入答案和S_i,再维护S_i即可。

偶环

假设这条边转了x次,答案为$\sum$ abs(Si-k*x),k只为1、-1或0,用中位数定理可求得最优的x

代码

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N=1e5+5;

int head[N],nxt[N<<1],to[N<<1],siz[N],z[N],k[N];
int n,m,num,X,Y,odd,sum,tot,mid;
LL ans;

int read()
{
    int x=0,p=1; char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') p=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*p;
}

void add(int x,int y)
{
    nxt[++num]=head[x],to[num]=y,head[x]=num;
}

void dfs1(int x,int fa)
{
    for(int i=head[x]; i ;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue ;    
        if(siz[y])
        {
            if(siz[y]==siz[x]) odd=1;
            X=x,Y=y;
        }
        else
        {
            siz[y]=-siz[x];
            dfs1(y,x);
        }
    }
}

void dfs2(int x,int fa)
{
    for(int i=head[x]; i ;i=nxt[i])
    {
        int y=to[i];
        if(y==fa || (x==X&&y==Y) || (x==Y&&y==X))
            continue ;
        dfs2(y,x);
        siz[x]+=siz[y];
        k[x]+=k[y];
    }
}

int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);

    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        add(x,y),add(y,x);
    }

    siz[1]=1;
    dfs1(1,0);
    for(int i=1;i<=n;i++) sum+=siz[i];

    if(n-1==m)
    { if(sum) return printf("-1\n"),0; }
    else
        if(odd)
        {
            if(sum&1) return printf("-1\n"),0;
            ans+=abs(sum>>1); 
            siz[X]-=sum>>1,siz[Y]-=sum>>1;
        }
        else
        {
            if(sum) return printf("-1\n"),0;
            k[X]=1,k[Y]=-1;
        }

    dfs2(1,0);
    for(int i=1;i<=n;i++)
        if(k[i]) z[++tot]=k[i]*siz[i];
        else ans+=abs(siz[i]);
    z[++tot]=0;
    sort(z+1,z+tot+1);
    mid=z[tot+1>>1];
    for(int i=1;i<=tot;i++) ans+=abs(z[i]-mid);

    printf("%lld\n",ans);
    return 0;
}

被if、else的嵌套卡了好久。。。

模拟赛AT2046 Namori 二分图

标签:否则   read   def   freopen   space   节点   平衡   整数   就是   

原文地址:https://www.cnblogs.com/lzqlalala/p/10479208.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!