单词拼接

时间限制: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

解析:

有向图G 为欧拉回路:
当且仅当G 的基图连通,且所有顶点的入度等于出度。
有向图G 为欧拉路:
当且仅当G 的基图连通,且只存在一个顶点u 的入度比出度大1、
只存在一个顶点v 的入度比出度小1,其它所有顶点的入度等于出度。本题还有要注意的一点就是:

单词的首字母应该看做是出度,尾字母看做是入度

代码一:----TLE
我先用并查集判断是否连通,然后再据欧拉路的条件判断是否能形成欧拉路,
最后才搜索字典序最小,超时也不足为奇,不过为此我也纠结了好几天,后来想了想可以不用使用并查集判断连通,可以再最后的搜索中边搜索边判断是否连通

View Code

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <iostream>
  5 #include <algorithm>
  6
  7 using namespace std;
  8
  9 const int M = 1005;
 10 struct word
 11 {
 12     char s[35];
 13     int start;
 14     int end;
 15 }str[M];
 16 int in_degree[26], out_degree[26]; // 分别记录入度和出度
 17 int father[26];   // 并查集中的数组
 18 bool use[26];   //记录首尾出现的字母,用并查集时即判断出现过的字母是否连通
 19 bool visit[M];  // 搜索路径时候回溯时候用的
 20 int ans[M];    // 结果序列
 21 int n, flagOfStart;
 22 /*要判断存在欧拉路径后输出字典序最小的路径,
 23 先把单词按字典序排序,然后判断是欧拉回路还是只是欧拉通路,
 24 如果是欧拉回路,直接从第0号单词开始搜,否则,找到出度比入度大1的
 25 那个单词开始搜标记为欧拉路起点的字母,flagOfStart即记录起点编号;
 26
 27
 28 int find_father(int i)
 29 {
 30     if(father[i] == -1)
 31         return i;
 32     else
 33         return find_father(father[i]);
 34 }
 35
 36 void merge(int num1, int num2)
 37 {
 38     num1 = find_father(num1);
 39     num2 = find_father(num2);
 40     if(num1 != num2)
 41         father[num1] = num2;
 42 }
 43
 44 void init()
 45 {
 46     memset(in_degree, 0, sizeof(in_degree));
 47     memset(out_degree, 0, sizeof(out_degree));
 48     memset(father, -1, sizeof(father));
 49     memset(visit, false, sizeof(visit));
 50     memset(use, false, sizeof(use));
 51     scanf("%d", &n);
 52     for(int i = 0; i < n; ++i)
 53     {
 54         scanf("%s", str[i].s);
 55         int len = strlen(str[i].s);
 56         str[i].start = str[i].s[0] - 'a';
 57         str[i].end = str[i].s[len-1] - 'a';
 58         use[str[i].start] = use[str[i].end] = true;
 59         merge(str[i].start, str[i].end);
 60         ++out_degree[str[i].start];
 61         ++in_degree[str[i].end];
 62     }
 63 }
 64
 65 bool judge()
 66 {
 67     flagOfStart = 0;
 68     int cnt_in = 0;
 69     int cnt_out = 0;
 70     int tmp = 0;
 71     for(int i = 0; i < 26; ++i) //并查集判断是否连通
 72     {
 73         if(use[i] && father[i] == -1)
 74         {
 75             ++tmp;
 76             if(tmp > 1)    // 不连通
 77                 return false;
 78         }
 79     }
 80     for(int i = 0; i < 26; ++i)  // 判断是否能形成欧拉路或欧拉回路
 81     {
 82         if(!use[i])
 83             continue;
 84         if(abs(in_degree[i] - out_degree[i]) >= 2)
 85             return false;
 86
 87         // 下边这点我把起点弄错了,害我调试了半天(我把出度和入度理解反了)
 88         if(in_degree[i] - out_degree[i] == 1) //入度比出度大一,若为欧拉路则为唯一的终点
 89             ++cnt_in;
 90         else if(in_degree[i] - out_degree[i] == -1)//入度比出度小一,若为欧拉路则为唯一的起点
 91         {
 92             ++cnt_out;
 93             flagOfStart = i;   // 若是欧拉路,则i必然是起点
 94         }
 95     }
 96     if(!flagOfStart)   //  如果是欧拉回路,则找到任意第一个出现过的字母作为搜索的起点即可
 97     {
 98         for(int i = 0; i < 26; ++i)
 99             if(use[i])
100             {
101                 flagOfStart = i;
102                 break;
103             }
104     }
105     if(cnt_out == 0 && cnt_in ==0 || cnt_out == 1 && cnt_in == 1)
106         return true;
107     return false;
108 }
109
110 bool cmp(word p, word q)
111 {
112     return strcmp(p.s, q.s) < 0;
113 }
114
115 void DFS(int cur)  // 在进行DFS的时候已经确定了本题的答案一定存在,
116 {                   //只是找到字典序最小的那组序列即可
117     if(cur == n)
118     {
119         for(int i = 0; i < n-1; ++i)
120             printf("%s.", str[ans[i]].s);
121         printf("%s\n", str[ans[n-1]].s);
122         return;
123     }
124     for(int i = 0; i < n; ++i)
125     {
126         if(str[i].start < flagOfStart || visit[i])
127             continue;
128         if(str[i].start > flagOfStart)
129             return;
130         ans[cur] = i;
131         visit[i] = true;
132         flagOfStart = str[i].end;
133         DFS(cur+1);
134         visit[i] = false;
135     }
136 }
137
138 int main()
139 {
140     int T;
141     scanf("%d", &T);
142     while(T--)
143     {
144         init();
145         if(!judge())
146         {
147             printf("***\n");
148             continue;
149         }
150         sort(str, str + n, cmp);
151         DFS(0);
152     }
153     return 0;
154 }

代码二: -----没用并查集,还是超时fuck。。。。。

View Code

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <iostream>
  5 #include <algorithm>
  6
  7 using namespace std;
  8
  9 const int M = 1005;
 10 struct word
 11 {
 12     char s[35];
 13     int start;
 14     int end;
 15 }str[M];
 16 int in_degree[26], out_degree[26];
 17 bool use[26];
 18 bool visit[M];
 19 int ans[M];
 20 int n, flagOfStart;
 21
 22 void init()
 23 {
 24     memset(in_degree, 0, sizeof(in_degree));
 25     memset(out_degree, 0, sizeof(out_degree));
 26     memset(visit, false, sizeof(visit));
 27     memset(use, false, sizeof(use));
 28     scanf("%d", &n);
 29     for(int i = 0; i < n; ++i)
 30     {
 31         scanf("%s", str[i].s);
 32         int len = strlen(str[i].s);
 33         str[i].start = str[i].s[0] - 'a';
 34         str[i].end = str[i].s[len-1] - 'a';
 35         use[str[i].start] = use[str[i].end] = true;
 36         ++out_degree[str[i].start];
 37         ++in_degree[str[i].end];
 38     }
 39 }
 40
 41 bool judge()
 42 {
 43     flagOfStart = 0;
 44     int cnt_in = 0;
 45     int cnt_out = 0;
 46     int tmp = 0;
 47     for(int i = 0; i < 26; ++i)
 48     {
 49         if(!use[i])
 50             continue;
 51         if(abs(in_degree[i] - out_degree[i]) >= 2)
 52             return false;
 53         if(in_degree[i] - out_degree[i] == 1) //入度比出度大一,若为欧拉路则为唯一的终点
 54             ++cnt_in;
 55         else if(in_degree[i] - out_degree[i] == -1)//入度比出度小一,若为欧拉路则为唯一的起点
 56         {
 57             ++cnt_out;
 58             flagOfStart = i;   // 若是欧拉路,则i必然是起点
 59         }
 60     }
 61     if(!flagOfStart)   //  如果是欧拉回路,则找到任意第一个出现过的字母作为搜索的起点即可
 62     {
 63         for(int i = 0; i < 26; ++i)
 64             if(use[i])
 65             {
 66                 flagOfStart = i;
 67                 break;
 68             }
 69     }
 70     if(cnt_out == 0 && cnt_in ==0 || cnt_out == 1 && cnt_in == 1)
 71         return true;
 72     return false;
 73 }
 74
 75 bool cmp(word p, word q)
 76 {
 77     return strcmp(p.s, q.s) < 0;
 78 }
 79
 80 bool DFS(int cur)
 81 {
 82     if(cur == n)
 83     {
 84         return true;
 85     }
 86     for(int i = 0; i < n; ++i)
 87     {
 88         if(str[i].start < flagOfStart || visit[i])
 89             continue;
 90         if(str[i].start > flagOfStart)
 91             return false;
 92         ans[cur] = i;
 93         visit[i] = true;
 94         flagOfStart = str[i].end;
 95         if(DFS(cur+1))
 96             return true;
 97         visit[i] = false;
 98     }
 99     return false;
100 }
101
102 int main()
103 {
104     int T;
105     scanf("%d", &T);
106     while(T--)
107     {
108         init();
109         if(!judge())
110         {
111
112         }
113         sort(str, str + n, cmp);
114         if(!DFS(0))
115         {
116            printf("***\n");
117             continue;
118         }
119         for(int i = 0; i < n-1; ++i)
120             printf("%s.", str[ans[i]].s);
121         printf("%s\n", str[ans[n-1]].s);
122     }
123     return 0;
124 }

代码三:----AC,哥桑心了

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 using namespace std;
  5 struct node
  6 {
  7     char s[31];
  8     int first,last;
  9 };
 10
 11 node a[1001];
 12 int degree_in[1001],degree_out[1001],m,order[1001];
 13 bool used[1001];
 14
 15 int f()
 16 {
 17     int x1,x2,ans=0,i;
 18     x1=x2=0;
 19     for(i=0;i<26;++i)
 20     {
 21         if(abs(degree_in[i]-degree_out[i])>=2)
 22             return -1;
 23         else if(degree_in[i]-degree_out[i]==1)
 24             x1++;
 25         else if(degree_in[i]-degree_out[i]==-1)
 26         {
 27             x2++;
 28             ans=i;
 29         }
 30     }
 31         if(x1>1||x2>1) //当时三个度时,必定是 12 和21,相同的不能大于等于2,不然不能构成欧拉回路
 32             return -1;
 33         else if(x1==0)
 34         {
 35             for(i=0;i<26;++i)
 36                 if(degree_out[i])
 37                     return i; //找到一个就行
 38         }
 39         else
 40             return ans;
 41
 42 }
 43 bool cmp(node a,node b)
 44 {
 45     return strcmp(a.s,b.s)<0;
 46 }
 47
 48 bool dfs(int st,int cnt)
 49 {
 50     int i;
 51     if(cnt==m)
 52         return 1;
 53     for(i=0;i<m;++i)
 54     {
 55         if(a[i].first<st||used[i])
 56             continue;
 57         else if(a[i].first>st)
 58             return false;
 59         used[i]=true;
 60         order[cnt]=i;
 61         if(dfs(a[i].last,cnt+1))
 62             return 1;
 63         used[i]=false;//回溯判断是否形成欧拉路径
 64     }
 65     return false;
 66 }
 67
 68
 69 int main()
 70 {
 71     int N,len,i,start;
 72     scanf("%d",&N);
 73     while(N--)
 74     {
 75         memset(used,false,sizeof(used));
 76         memset(degree_out,0,sizeof(degree_out));
 77         memset(degree_in,0,sizeof(degree_in));
 78         scanf("%d",&m);
 79         for(i=0;i<m;++i)
 80         {
 81             scanf("%s",a[i].s);
 82             len = strlen(a[i].s);
 83             a[i].first =a[i].s[0]-'a';
 84             a[i].last =a[i].s[len-1]-'a';
 85             degree_out[a[i].s[0]-'a']++;
 86             degree_in[a[i].s[len-1]-'a']++;//注意这里的入肚出度
 87         }
 88         start=f();
 89         if(start ==-1)
 90         {
 91             printf("***\n");
 92             continue;
 93         }
 94         sort(a,a+m,cmp);
 95         if(!dfs(start,0))
 96         {
 97             printf("***\n");
 98             continue;
 99         }
100        printf("%s",a[order[0]].s);
101       for(i=1;i<m;i++)
102          printf(".%s",a[order[i]].s);
103       printf("\n");
104     }
105     return 0;
106 }

NYOJ-99 单词拼接(欧拉+回溯)相关推荐

  1. NYOJ 99单词拼接(有向图的欧拉(回)路)

    1 /* 2 NYOJ 99单词拼接: 3 思路:欧拉回路或者欧拉路的搜索! 4 注意:是有向图的!不要当成无向图,否则在在搜索之前的判断中因为判断有无导致不必要的搜索,以致TLE! 5 有向图的欧拉 ...

  2. NYOJ 99 单词拼接

    单词拼接 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 给你一些单词,请你判断能否把它们首尾串起来串成一串. 前一个单词的结尾应该与下一个单词的道字母相同. 如 alo ...

  3. C语言DFS(7)___单词拼接(NYoj 99)

    单词拼接 描述 给你一些单词,请你判断能否把它们首尾串起来串成一串. 前一个单词的结尾应该与下一个单词的道字母相同. 如 aloha dog arachnid gopher tiger rat 可以拼 ...

  4. NYOJ - 99:单词拼接

    单词拼接 来源:NYOJ 标签:图论,欧拉图,欧拉路径 参考资料: 欧拉图:https://baike.baidu.com/item/%E6%AC%A7%E6%8B%89%E5%9B%BE 相似题目: ...

  5. NYOJ 99-单词拼接

    单词拼接 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 题目链接:点击打开链接 描述 给你一些单词,请你判断能否把它们首尾串起来串成一串. 前一个单词的结尾应该与下一个单词的 ...

  6. SGU101 求有重边的无向图欧拉迹

    题意:好多木棒,俩端有数字(0--6)标记,按数字相同的端首尾相连成一条直线(木棒可以相同).即求有重边的无向图欧拉迹. 先判定是否为欧拉图,俩个条件,不说了.如果是欧拉图,输出路经. 方法:dfs遍 ...

  7. 宏光MINI EV收割的年轻人,又被苏宁、小米、欧拉盯上了

    (图片来源于网络,侵删) 文 | 螳螂财经(ID:TanglangFin) 作者|易不二 "人民需要什么,五菱就造什么." 五菱这句话很真诚,但毫无疑问有吹牛的成份在.毕竟,人类的 ...

  8. LightOJ1298 One Theorem, One Year(DP + 欧拉函数性质)

    题目 Source http://www.lightoj.com/volume_showproblem.php?problem=1298 Description A number is Almost- ...

  9. [Project Euler] 来做欧拉项目练习题吧: 题目004

        [Project Euler] 来做欧拉项目练习题吧: 题目004 周银辉 问题描述: A palindromic number reads the same both ways. The l ...

最新文章

  1. 【安卓开发】Layout Inflation不能这么用
  2. MySQL安装错误——Access denied for user 'root'@'localhost' (using password: YES)
  3. Web API——添加Swagger、SQL Server、日志记录、导出到Excel和Docker
  4. DenyHosts安装及配置
  5. 学习总结-《父与子的编程之旅》chapter 9
  6. 周边pd是什么意思_pd是什么意思?饭圈说的pd是什么意思
  7. 小白从零开发鸿蒙小游戏(1)“数字华容道”—【深鸿会学习小组学习心得及笔记】
  8. Cisco 防火墙 SSH配置
  9. LaTex图表中英文标题,中英文图表目录
  10. LPMS-B2 数据采集源码分析
  11. typora插入代码设置_Typora快捷键
  12. w ndows10支持微信吗,windows10系统怎样安装微信客户端
  13. WebDAV之葫芦儿·派盘+小书匠
  14. 20191027(32)RT-Thread SPI 设备挂载——ADS1256 后续提供具体实现源码(stm32f407)
  15. Tesla M40 使用分享
  16. LeetCode第258场周赛
  17. oracle初始化参数详解
  18. 决策树算法_基本思想
  19. Android自定义UI陷阱 LayoutInflater from inflate 一定不能工作在父类或虚类里
  20. 人机协作机器人发展趋势_未来10年机器人三大发展趋势

热门文章

  1. 成员缩写_青春有你2snh48成员都有谁 10名SNH48女团成员介绍
  2. acwing----春季每日一题2022篇(一)
  3. 笔记本电脑linux系统下载,给笔记本电脑装Linux系统
  4. 笔记-项目范围管理-项目范围说明书
  5. 笔记-高项案例题-2018年上-质量管理
  6. Pygame介绍以及下载
  7. 从冲咖啡看统计过程控制
  8. flutter中state详解
  9. 计算机组成原理(分析计算题解析)内附填空,选择,解答题答案
  10. php计算波动率,单向波动率差值研究:单向波动差值实现绝对收益