zoukankan      html  css  js  c++  java
  • poj 2337 Catenyms

    再学欧拉路

    无力再写题解报告了,最近写得最难受的一道题,前前后后调试了有10来个小时,就一个这么个BUG

    #define N 30

    #define MAX 1010

    开某些数组的时候把N和MAX写反了

    但是…………代码还是有问题的,G++一直过不了,一直是WA,C++可以过,等下还要调试,一定要把G++给过了

    题意:和poj 1386 是一样的题目,不过这次要输出路径,而且要字典序最小

    做法:用邻接表来构建有向图(我的构建方法和网上找来的不一样,不是用白书介绍的那种模拟链表的头插法,而是直接一点,比较然后插入,已有的元素向后移,感觉在时间上没什么差距)。然后用并查集来判断有向图的基图是否连通(其实直接用邻接矩阵再DFS来判断连通也行,这里最多就26个顶点,要判断基图连通其实所用时间也差不多吧,反正不会TLE什么的),同时要记录每个点的入度和出度,然后还要判断度是否符合欧拉路的要求,最后DFS输出路径

    不多说了,无力写了,很多内容都已经在代码的注释中

    #include <stdio.h>
    #include <string.h>
    #include <cmath>
    //#include <algorithm>
    //using namespace std;
    #define N 30      //顶点个数,即最多26个字母
    #define MAX 1010  //单词个数最多1000
    #define LEN 25    //单词长度最多为20
    char word[N][LEN]; //单词表
    bool w[MAX];        //标记哪个单词被用过
    int in[N],out[N];  //26个顶点的入度和出度
    struct edgenode   //邻接表的节点
    {
        int e,v;  
        //e是第几条边也就是单词表中的第e个单词,v是有向边<u,v>的顶点v
    };
    struct node
    {
        int c;  //有向边<u,v>的顶点u一共有c条边,也就是邻接表的长度
        struct edgenode b[MAX]; //邻接表
    }a[N];  //26个顶点
    int minnum;   //字典序最小的那个单词的编号
    int start,eend;  //记录欧拉道路的起点和终点
    //bool g[N][N],vis[N];  //构建基图判断图连通
    int n;
    int stack[MAX],top;  //用于路径保存
    int father[N];
    void init()
    {
        for(int i=1; i<=26; i++)
            father[i]=i;
        //memset(g,0,sizeof(g));
        //memset(vis,0,sizeof(vis));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(a,0,sizeof(a));
        memset(w,0,sizeof(w));
        memset(stack,0,sizeof(stack));
        top=-1;
        return ;
    }
    
    void addedge(int u ,int v , int e) //第e条有向边(即第e个单词)<u,v>
    {
        int i,j;
        struct edgenode tmp;
        tmp.e=e;
        tmp.v=v;
        for(i=1; i<=a[u].c; )
            if( strcmp( word[e] , word[a[u].b[i].e]) >= 0 ) 
                i++;
            else //在i位置插入
                break;
        for(j=a[u].c; j>=i; j--)
            a[u].b[j+1]=a[u].b[j];
        a[u].b[i]=tmp;
        a[u].c++;
        return ;
    }
    int find(int x)
    {  return father[x]==x ? x : (father[x]=find(father[x]) );   }
    void SET(int u , int v)
    {
        int x,y;
        x=find(u);
        y=find(v);
        if(x!=y)
            father[x]=y;
        return ;
    }
    void input()
    {
        int i,j,u,v,len,x,y;
        scanf("%d",&n);
        for(minnum=1, i=1; i<=n; i++)
        {
            scanf("%s",word[i]);
            len=strlen(word[i]);
            u=word[i][0]-'a'+1;
            v=word[i][len-1]-'a'+1;
            //得到有向边<u,v>
            addedge(u,v,i);  //往点u中添加第i条有向边<u,v>
            out[u]++;
            in[v]++;
            //g[u][v]=g[v][u]=1;  //构建基图
            SET(u,v);
            if( strcmp(word[i],word[minnum])<0 )
                minnum=i;  //记录字典序最小的单词
        }
        
    
        return ;
    }
    int Degree()  //判断图的度是否满足要求
    {
        int i,n1,n2;
        n1=n2=0; start=eend=0;
        for(i=1; i<=26; i++)
        {
            if(out[i]-in[i]==1)
            {
                n1++;
                if(n1>1) break;
                start=i;
            }
            else if(in[i]-out[i]==1)
            {
                n2++;
                if(n2>1) break;
                eend=i;
            }
            else if( abs(in[i]-out[i])>1 )
                break;
        }
    
        if(i<=26)  
            return 0;  //没有完全扫描整个数组说明不存在欧拉路
        else if(n1==0 && n2==0)  //可以从任意顶点出发
        {
            start=word[minnum][0]-'a'+1;
            return 1;
        }
        else if(n1==1 && n2==1)
            return 1;
        else
            return 0;
    }
    
    
    void dfs(int u ,int ee)
    {
        int i,e,v;
        for(i=1; i<=a[u].c; i++) //扫描点u的邻接表从尾部扫描回来
        {
            e=a[u].b[i].e;  //取出这条边
            v=a[u].b[i].v;  //取出有向边<u,v>的另一个顶点v
            if(!w[e])
            {
                w[e]=1;
                dfs(v,e);         //递归顶点v;
                
            }
        }
        stack[++top]=ee;
        return ;
    }
    
    void printfff()
    {
        int i;
        for(i=top-1; i>=0; i--)
            if(i!=0)
                printf("%s.",word[stack[i]]);
            else 
                printf("%s\n",word[stack[i]]);
    }
    
    int connect()
    {
        int tmp,i,count;
    
            //并查集判断图连通,不能超过1个顶点和它的双亲father[i]相同
            //超过1过说明不连通
        for(count=0,i=1; i<=26; i++)
            if(in[i] || out[i])
                if( father[i]==i )
                    count++;
        if(count>1)
            return 0;
        else 
            return 1;
    }
    int main()
    {
        int T,tmp;
        scanf("%d",&T);
        while(T--)
        {
            init();
            input();
            if(connect())  //图连通
            {
                if(Degree())  //存在欧拉路径
                {
                    dfs(start,0);
                    printfff();
                }
                else  //度不符合
                {
                    //printf("图连通但是度不符合\n");
                    printf("***\n");
                }
            }
            else
            {
                //printf("图不连通\n");
                printf("***\n");
            }
            
        }
    
        return 0;
    }
  • 相关阅读:
    md笔记——HTTP知识
    百万表格难题
    微信接口改良
    md笔记——正则学习
    md笔记——编程术语
    md笔记——微信JS接口
    md笔记——使用 @font-face 引入你喜欢的字体
    博客一年记
    “挨踢”的伙食怎样?
    比尔·盖茨早年
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2764294.html
Copyright © 2011-2022 走看看