NYOJ99 欧拉图

单词拼接

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 5
描述

给你一些单词,请你判断能否把它们首尾串起来串成一串。

前一个单词的结尾应该与下一个单词的道字母相同。

aloha

dog

arachnid

gopher

tiger

rat

 

可以拼接成:aloha.arachnid.dog.gopher.rat.tiger

输入
第一行是一个整数N(0<N<20),表示测试数据的组数
每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。
输出
如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")
如果不存在拼接方案,则输出
***
样例输入
2
6
aloha
arachnid
dog
gopher
rat
tiger
3
oak
maple
elm
样例输出
aloha.arachnid.dog.gopher.rat.tiger
***
来源
Waterloo local 2003.01.25 /POJ
上传者

张云聪



1.无向图G是欧拉图的充分必要条件是G 是连通图并且没有奇数度顶点。

2.无向图G是半欧拉图的充分必要条件是G是连通的并且恰好有两个奇数度顶点。

3.有向图G是欧拉图的充分必要条件是图是强连通,并且每个定点的入度等于出度。

4.有向图G是半欧拉图的充分必要条件是图单向连通并且恰好有两个奇数度顶点,这两个奇数度顶点一个的出度比入度大1,一个刚好反过来,其余的顶点的出度等于入度。

5.G是非平凡的欧拉图当且仅当G是连通的并且是若干个边不重合的圈的并。


代码如下:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn = 1010;
const int maxm = 30;
int in[maxm],out[maxm],route[maxn];
bool vis[maxn];
struct node{
   char s[35];
   int head,tail;
}words[maxn];
int n;

bool cmp(node a, node b){return strcmp(a.s,b.s)<0;}

void init(){
    int len;
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for (int i=0; i<n; i++){
        scanf("%s",words[i].s);
        len = strlen(words[i].s);
        words[i].head = words[i].s[0] - 'a';
        words[i].tail = words[i].s[len-1] - 'a';
        out[words[i].head]++;
        in[words[i].tail]++;
    }
}

int euler(){
   int start = -1 , End = -1;
   for (int i=0; i<26; i++){
       if (out[i]!=in[i]){
          if (out[i]-in[i]==1 && start==-1) start = i;
          else if (out[i]-in[i]==-1 && End == -1) End = i;
          else return -1;
       }
   }

   if (start>-1 && End>-1) return start;
   if (start == -1 && End == -1) {
         for (int i=0; i<26; i++) if (out[i]!=0) return i;
   }
   return -1;
}

bool dfs(int x, int cnt){
    if (cnt==n) return 1;
    for (int i=0; i<n; i++){
        if (vis[i] || words[i].head<x) continue;
        else if (words[i].head>x) return 0;
        else {
            route[cnt] = i;
            vis[i] = 1;
            if (dfs(words[i].tail,cnt+1)) return 1;
            vis[i] = 0;
        }
    }
    return 0;
}

int T;
int main(){
    scanf("%d",&T);
    while (T--){
        init();
        int start = euler();
        if (start==-1) {printf("***\n"); continue;}
        sort(words,words+n,cmp);
        if (dfs(start,0)){
            printf("%s",words[route[0]].s);
            for (int i=1; i<n; i++) printf(".%s",words[route[i]].s);
            printf("\n");
        }
        else printf("***\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值