bzoj2503 相框——思路

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2503

思路题;

首先,这种问题应该注意到答案只跟度数有关,跟其他什么连接方法之类的完全无关;

关注最终状态,每个点度数都是2,所以对于原来度数不是2的需要进行处理;

也就是度数大于2的进行一次操作分成若干个2,如果是奇数那么留下一个1的等待合并,可以知道最终一定有偶数个度数为1的点;

然后考虑不是一个连通块的情况,需要把所有连通块变成链,再把它们连起来;

如果之前拆分过点,那么可以顺便多拆出两个度数为1的点,不损耗次数;

而如果原来就是一个欧拉回路,那么需要多拆一次;

然后合并,答案加上 度数为1的点数/2;

锻炼思路和码力啊!

参考TJ:https://blog.csdn.net/PoPoQQQ/article/details/48031135

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=150005;
int n,m,deg[maxn],fa[maxn],ans,sum,cnt;
bool split[maxn],odd[maxn];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<maxn;i++)fa[i]=i;//maxn!!
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
//        if(!x){deg[y]++; continue;}
//        if(!y){deg[x]++; continue;}
        if(!x)x=++n;
        if(!y)y=++n;
        deg[x]++; deg[y]++; fa[find(x)]=find(y);
    }
    for(int i=1;i<=n;i++)
    {
        if(deg[i]>2)ans++,split[find(i)]=1;
        if(deg[i]%2)sum++,odd[find(i)]=1;;
        if(find(i)==i&&deg[i])cnt++;//deg[i]!
    }
    for(int i=1;i<=n;i++)
        if(find(i)==i&&!odd[i]&&deg[i]&&cnt>1)
        {
            sum+=2;
            if(!split[i])ans++;
        }
    printf("%d",ans+sum/2);
    return 0;
}

 

posted @ 2018-07-09 10:22  Zinn  阅读(158)  评论(0编辑  收藏  举报