欧拉路 小结(POJ 2337 为例子)

最近把拓扑排序和欧拉路看了一遍,前面已经说了拓扑排序,今天就来说说一下,欧拉路。

从POJ 2337 这道题开始说吧。

这道的题目的意思是给你一些单词,问你可不可以首尾连接起来。

思路:判断是不是连通图+欧拉图判断+输出欧拉路路径(字典序最小的)

先来说下是不是连通图,要用到并查集(自己复习了一下, 就明了)

简单说下,就是把一个节点的上司给另一个节点,省去中间的领导

直接看他隶属哪个最大的头目。然后再看看是不是所有人的老大是不是一个人~。


欧拉路的判断:

无向欧拉图:所有节点的度数(出度+入度)都是偶数

或者只有两个点的度数为奇数,这两个点是起点和中点

有向欧拉图:所有点的入度=出度

或者只有一点的入度=出度+1(这是起点)和只有一点的出度=入度+1(这点是起点)


然后是路径输出,用到DFS,用到的是图论中的路径连接那块的知识。

类似于向前星。

代码可能比较多,但是以简单的想法慢慢写的,好理解。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000001;
int p[maxn];
int c1[maxn*3],c2[30],cnt1,cnt2,cnt;
int cnt_in[maxn],cnt_out[maxn],kk[maxn];
int n;
int kaitou;//第一个dfs的开头
struct P
{
    int st,ed;
    bool del;
}edge[maxn];
int vis[maxn];
struct node
{
    char s[21];
    bool operator<(const node &C)const
    {
        return strcmp(s,C.s)<0;
    }
} str[maxn];
int cmp(char *s1,char *s2)
{
    return strcmp(s1,s2)<0;
}
int cha(int x)
{
    return x==p[x]?x:cha(p[x]);
}
void bing(int x,int y)
{
    x=cha(x);
    y=cha(y);
    if(x!=y)
        p[x]=y;
}
int chahao(int x)
{
    for(int i=0; i<cnt2; i++)
        if(c2[i]==x)
            return 1+i;
}
int panduan1()
{
    memset(cnt_in,0,sizeof(cnt_in));
    memset(cnt_out,0,sizeof(cnt_out));
    for(int i=1; i<=cnt2; i++)
        p[i]=i;
    for(int i=0; i<n; i++)
    {
        int len=strlen(str[i].s);
        int x=str[i].s[0]-'a'+1;
        int y=str[i].s[len-1]-'a'+1;
        x=chahao(x);
        y=chahao(y);
        cnt_out[x]++;
        cnt_in[y]++;
      //  AddEdge(i,y);
      edge[i].st=x;
      edge[i].ed=y;
      edge[i].del=false;
        bing(x,y);
    }
    int sum=0;
    for(int i=1; i<=cnt2; i++)
        if(i==p[i])
            sum++;
    if(sum>1)
        return 0;
    return 1;
}
int panduan2()
{
    int f1=0,f2=0,sum=0;
    int t;
    // for(int i=1;i<=cnt2;i++)
   // printf("%d %d\n",cnt_in[i],cnt_out[i]);
    for(int i=1; i<=cnt2; i++)
    {
        if(cnt_in[i]==cnt_out[i])
            sum++;
        if(cnt_in[i]==cnt_out[i]+1)
            f1++;
        if(cnt_out[i]==cnt_in[i]+1)
        {
            t=i;
            f2++;
        }
    }
  //  printf("%d %d %d\n",sum,f1,f2);
    kaitou=edge[0].st;
    if(cnt2==1)
        return 1;
    if(f1==1&&f2==1)
    {
        kaitou=t;
        return 1;
    }
    if(sum==cnt2)
        return 1;
    return 0;
}
void dfs(int u)
{

   for ( int i = 0; i < n ;i++ )
	{
		if ( ! edge[i].del && edge[i].st == u )
		{
			edge[i].del = true;
			dfs ( edge[i].ed );
			kk[cnt++] = i;
		}
	}
}
void dfs_out()
{
    memset(vis,0,sizeof(vis));

    dfs(kaitou);
    printf("%s",str[kk[cnt-1]].s);
    for(int i=cnt-2;i>=0;i--)
        printf(".%s",str[kk[i]].s);
    puts("");
}

int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {

        scanf("%d",&n);
        cnt=0;
        for(int i=0; i<n; i++)
            scanf("%s",str[i].s);
        sort(str,str+n);
        // for(int i=0;i<n;i++)
        //printf("%s ",str[i].s);
        cnt1=0,cnt2=1;
        for(int i=0; i<n; i++)
        {
            int len=strlen(str[i].s);
            int x=str[i].s[0]-'a'+1;
            int y=str[i].s[len-1]-'a'+1;
            c1[cnt1++]=x;
            c1[cnt1++]=y;
        }
        //for(int i=0;i<cnt1;i++)
        // printf("%d ",c1[i]); puts("");
        sort(c1,c1+cnt1);
        c2[0]=c1[0];
        for(int i=1; i<cnt1; i++)
        {
            if(c1[i]!=c1[i-1])
                c2[cnt2++]=c1[i];
        }
        //保存不同的字母
        //  for(int i=0;i<cnt2;i++)
        // printf("%d ",c2[i]);
        if(panduan1()==0)//判断是不是连通图
        {
           // puts("11111");
            puts("***");
        }
        else
        {
            if(panduan2()==0)//判断是不是欧拉图,即一笔画
            {
                puts("***");
            }
            else
            {
                dfs_out();
            }
        }

    }
    return 0;
}


你可能感兴趣的:(欧拉路 小结(POJ 2337 为例子))