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;

}

 

你可能感兴趣的:(poj)