bzoj 2503 相框 欧拉回路

 

转载请注明出处:

http://www.cnblogs.com/hzoi-wangxh/p/7738618.html

 

2503: 相框

Description

       P大的基础电路实验课是一个无聊至极的课。每次实验,T君总是提前完成,管理员却不让T君离开,T君只能干坐在那儿无所事事。
       先说说这个实验课,无非就是把几根导线和某些元器件(电阻、电容、电感等)用焊锡焊接起来。
       为了打发时间,T君每次实验做完后都在焊接一些诡异的东西,这就是他的杰作:

       T君不满足于焊接奇形怪状的作品,强烈的破坏欲驱使他拆掉这个作品,然后将之焊接成规整的形状。这会儿,T君正要把这个怪物改造成一个环形,当作自己的相框,步骤如下:

T君约定了两种操作:

1.      烧熔一个焊点:使得连接在焊点上的某些导线相分离或保持相连(可以理解为:把焊点上的导线划分为若干个类,相同类中的导线相连,不同类之间的导线相离)

2.      将两根导线的自由端(即未与任何导线相连的一端)焊接起来。

 

例如上面的步骤中,先将A点烧熔,使得导线1与导线2、4点分离;再将D点烧熔,使得4、5与3、7相离;再烧熔E,使7与6、8相离;最后将1、7相连。

T君想用最少的操作来将原有的作品改造成为相框(要用上所有的导线)。

 

Input

输入文件的第一行共有两个整数nm — 分别表示原有的作品的焊点和导线的数量 (0 ≤ n ≤ 1 000, 2 ≤ m ≤ 50 000)。焊点的标号为1~n。 接下来的m行每行共有两个整数 — 导线两端所连接的两个焊点的标号,若不与任何焊点相连,则将这一端标号为0。

原有的作品可能不是连通的。

某些焊点可能只有一根导线与之相连,在该导线的这一端与其他导线相连之前,这些焊点不允许被烧熔。

某些焊点甚至没有任何导线与之相连,由于T君只关心导线,因此这些焊点可以不被考虑。

 

 

Output

 

       输出文件只包含一个整数——表示T君需要将原有的作品改造成相框的最少步数。

Sample Input

6 8
1 2
1 3
3 4
1 4
4 6
5 6
4 5
1 5

Sample Output

4

HINT

30%的数据中n≤10;


100%的数据中n≤1000。


题解:
据观察,我们可以发现焊接的次数之与每一个点的入度有关。
当这一条路是欧拉回路时,这一个联通块内每一个节点的入度都为2。
所以对于每一个联通块,若入度为奇数,零头加1;若入度大于2,一定会拆一次,ans+=1;对于某一个方向为0的点,新开一个节点即可。
如果对于某一个联通块它本身就是欧拉回路并且不止一个联通块,我们需要拆一次,零头+2;
对于自环,我们可以发现它对结果无影响,完全可以归入上几类的讨论且不违背,像其他的一样处理即可。
注意开大内存,最好到m(max)*2+n(max);

附上代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int ru[101100],n,m,sum,fa[101010],ling,cun[101010],num,ans;
bool pd[101010],fen[101010];
int find(int);
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if(x==0) ++n,fa[n]=n,x=n;
        if(y==0) ++n,fa[n]=n,y=n;
        ru[x]++;ru[y]++;
        int fx=find(x),fy=find(y);
        fa[fx]=fy;
    }
    for(int i=1;i<=n;i++){
        if(ru[i]==0) continue;
        find(i);
        if(fa[i]==i) cun[++num]=i;
        if((ru[i]&1)==1) ling+=1,pd[fa[i]]=1;
        if(ru[i]>2) fen[fa[i]]=1,ans+=1;
	}
    if(num!=1)
        for(int i=1;i<=num;i++)
            if(pd[cun[i]]==0){
                ling+=2;
                if(fen[cun[i]]==0) ans+=1;
            }
    ans+=ling/2;
    printf("%d",ans);
    return 0;
}
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}


 

posted @ 2017-10-01 21:22  hzoi_wangxh  阅读(477)  评论(0编辑  收藏  举报