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;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2764294.html