zoukankan      html  css  js  c++  java
  • 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]);
    }


  • 相关阅读:
    UVaLive 7362 Farey (数学,欧拉函数)
    UVaLive 7361 Immortal Porpoises (矩阵快速幂)
    UVaLive 7359 Sum Kind Of Problem (数学,水题)
    CodeForces 706D Vasiliy's Multiset (字典树查询+贪心)
    负载均衡服务器
    集群-如何理解集群?
    架构规划
    领域模型
    状态图
    E-R图
  • 原文地址:https://www.cnblogs.com/hzoi-wangxh/p/7738618.html
Copyright © 2011-2022 走看看