poj2337-G - Catenyms -有向图欧拉路径dfs输出

 http://poj.org/problem?id=2337

给你一组N个单词,现在要你输出这样一组单词序列。该序列包含了所有N个单词,且该序列中的前一个单词的最后一个字母与后一个单词的第一个字母相同。如果存在多个这种首尾相连的序列,就输出字典序最小的那个即可。

首先得判断图的连通性,并查集判断

1.图连通2.每个点的入度等于出度dfs起点为第一个点

或有两个点入度不等于出度,且一个点出度比入度大一(起点)作为dfs起点,另一个点入度比出度小一(终点)

还有这里得字典序从大到小建图,这样遍历的时候就变成小到大,最后再逆序输出

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<set>
#include<vector>
#include<sstream>
#include<queue>
#define PI 3.1415926535897932384626
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2010;
struct Edge
{
    int to,next;
    int flag;
    int index;
}edge[maxn];
int pre[30],in[30],out[30],tot,head[maxn];
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    edge[tot].index=w;
    //cout<<edge[tot].next<<endl;
    edge[tot].flag=false;
    head[u]=tot++;
    //cout<<u<<":"<<head[u]<<endl;
}
int find(int x)
{
    return x==pre[x]?x:pre[x]=find(pre[x]);
}
void iset()
{
    for(int i=0;i<30;i++)
    {
        pre[i]=i;
        in[i]=0;
        out[i]=0;
    }
}
void mix(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        pre[fy]=fx;
    }
}
int cnt;
int ans[1010];
void dfs(int u)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
        if(!edge[i].flag)
    {

        edge[i].flag=true;
        dfs(edge[i].to);
        ans[cnt++]=edge[i].index;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    string str[1010];
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            cin>>str[i];
        }
        sort(str,str+n);
        init();
        iset();
        int start=str[0][0]-'a';
        for(int i=n-1;i>=0;i--)
        {
            //cout<<str[i]<<endl;
            int u,v;
            u=str[i][0]-'a';
            v=str[i][str[i].length()-1]-'a';
            addedge(u,v,i);
            mix(u,v);
            out[u]++;
            in[v]++;
        }
        int root=0;
		for(int i=0;i<27;++i)
		{
			if((in[i] || out[i])&&i==pre[i])
			{
				root++;
			}
		}
		if(root!=1)
		{
			printf("***\n");
			continue;
		}
		int flag=1;
		int num1=0;int num2=0;
		for(int i=0;i<30;++i)
		{
			if(in[i]!=out[i])
			{
				if(in[i]==out[i]+1){++num1;}
				else if( out[i]==in[i]+1){++num2;start=i;}
				else{flag=0;break;
				}
			}
		}
		//cout<<start<<endl;
		if(num1 && num2 && num1+num2>2)flag=0;
		if(flag==0)
		printf("***\n");
		else{
            cnt=0;
            dfs(start);
            //cout<<cnt<<endl;
            for(int i=cnt-1;i>=0;i--)
            {//cout<<"1111"<<endl;
                cout<<str[ans[i]];
                if(i==0)cout<<endl;
                else printf(".");
            }
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷丘-CODER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值