zoukankan      html  css  js  c++  java
  • uva 10054 The Necklace

    推荐技术公众号:不爱睡觉的大猪

    题意:给你n个珠子,一个珠子分为两半有两种颜色,用1到50来表示50种不同的颜色。把这些珠子串起来,两个紧挨着的珠子要满足一个条件就是接触的那部分颜色要相同

    例如(1,2)(2,4),两个珠子的接触部分颜色相同都为2。当然,因为珠子最后是连成环的,第一个珠子和最后一个珠子也会接触,也要买满足这个条件

    先输入T,有T组数据

    输入n,有n个珠子

    下面n行每行两个数字表示这个珠子的两个颜色,然后问你能不能连成一条链,能的话输出任意一种连接情况即可,不能的话输出失败

    其本质是欧拉回路,欧拉回路的题只做过每背景的裸题,第一次做这个,想不到是欧拉回路,然后想了差不多一个小时才想到是欧拉回路,说说思考的思路

    其实1到50代表50钟颜色也就是50个点,一个珠子的信息例如(1,2)其实就是一个无向边(1,2),注意是无向边,因为珠子是可以转过来的,(1,2)=(2,1),那么无疑就可以建立一个图了

    另外,给你的n个珠子如果是能连成链的话,那么其实任意一个珠子都可以作为起点,最后要回到自己,然后就想到,那不就是在已有的图中进行遍历,遍历了所有的点然后回到自己吗?怎么那么像那么欧拉的………………然后再思考了一些细节,稍微推理了一下确定了就是要判断是否存在欧拉回路,若存在即输出路径

    无向图的欧拉回路判断和路径输出

    1.判断所有的点的度是否为偶数,如果有点不为偶数,则不存在欧拉回路

    2.满足1的条件下,判断所给的图是否连通,不连通也不是欧拉回路

    3.满足1和2的就是欧拉回路,然后dfs逆序输出路径,主要一定要逆序,不逆序是错的,后面会解释

    经过有意的测试那先这道题是不需要判断图连通的,也就是所给数据图一定是连通的,所以直接判断度即可

    先给出代码,在详细分析

    #include <stdio.h>
    #include <string.h>
    #define N 55
    #define MAX 1010
    int g[N][N],vis[N];
    int d[N];
    int n;
    
    
    void euler(int u)
    {
        int v;
        for(v=1; v<=50; v++) 
            if(g[u][v])
            {
                g[u][v]--;
                g[v][u]--;
                euler(v);
                printf("%d %d\n",v,u);
                //一定要逆序输出
            }
    }
    int main()
    {
        int t,T;
        int i,j;
        int u,v;
        int count,max,start;
        scanf("%d",&T);
        for(t=1 ;t<=T; t++)
        {
            memset(g,0,sizeof(g));
            memset(vis,0,sizeof(vis));
            memset(d,0,sizeof(d));
            scanf("%d",&n);
            for(i=1 ;i<=n; i++)
            {
                scanf("%d%d",&u,&v);
                d[u]++;
                d[v]++;
                g[u][v]++;
                g[v][u]++;
            }
            printf("Case #%d\n",t);
    
            //图是连通的,要判断所有点的度是否有为偶数    
            max=0; start=0;
            for(i=1 ;i<=50; i++)
                if( d[i]%2 )
                    break;
            if(i<=50)
                printf("some beads may be lost\n");
            else  //图连通而且所有点的度都为偶数,则是一个欧拉回路,输出路径
                for(i=1; i<=50; i++)
                    euler(i);
    
            if(t!=T) printf("\n");
        }
        return 0;
    }

    整个问题容易WA的地反是输出路径,其实就是一个dfs

    for(i=1; i<=50; i++)
        euler(i);
    
    
    void euler(int u)
    {
        int v;
        for(v=1; v<=50; v++) 
            if(g[u][v])
            {
                g[u][v]--;
                g[v][u]--;
                euler(v);
                printf("%d %d\n",v,u);
                //一定要逆序输出,而且注意输出的边是(v,u)而不是(u,v)
            }
    }

     

    如果写成这样是错的

    void euler(int u)
    {
        int v;
        for(v=1; v<=50; v++) 
            if(g[u][v])
            {
                g[u][v]--;
                g[v][u]--;
           printf("%d %d\n",u,v);

           euler(v);
        //这样相当于顺序输出
            }
    }

    在输入的时候使会有重边的,也就是g[i][j]的值不一定只是为1

    然后从一个点出发,找到和他相连的点,然后删除这条无向边,所以是  g[u][v]--;   g[v][u]--;  然后就去dfs下一个点v,最后在递归返回的时候才输出路径,也就是逆序输出,为什么要逆序输出了

    因为和当前点i相连的点可能不止一个

    例如当前点是1,上一条边是(3,1) . 而和1相连的点有2,7,11,能分成3个方向

    往2的方向有:(1,2) (2,4)

    往7的方向有:(1,7)(7,5)(5,6)

    往11的方向有:(1,11)(11,12)(12,13)

    如果顺序输出将会是

    3 1

    1 2

    2 4

    1 7

    7 5

    5 6

    1 11

    11 12

    12 13

     当找到起点之后,将起点压入栈中,然后访问与顶点相连的一个顶点,将该顶点压入栈中,同时删除这条边,然后继续DFS寻找顶点,并同样压栈、删除,最后,直到走到一个没有任何边与它相连的顶点(可能是起始点,也可能不是),便开始进行回溯,(回溯的同时进行弹栈,弹栈的结果也就是欧拉回路的逆序输出结果),回溯的过程就是寻找相连路径的过程,如果回溯的过程中发现仍然有边与当前顶点相连,那么继续从这个顶点沿着未删除的边去DFS,同时进行压栈等一系列操作,最后,必定会回到该点,然后继续回溯,直到顶点,逆序输出,结束

     
     
  • 相关阅读:
    搜狗输入法ubuntu
    数学
    1
    狗蚂蚁, 模拟题.
    最小公倍数
    哈夫曼费用计算C++
    C++十进制到任意进制
    【Django QuerySet API009】
    【Django模型(数据库)008】
    【Django模板进阶007】
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2762371.html
Copyright © 2011-2022 走看看