题目链接>>>>>>
题目大意:
给出一些字符串,问能否将这些字符串 按照 词语接龙,首尾相接 的规则 使得每个字符串出现一次
如果可以 按字典序输出这个字符串序列
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #define M 1050 using namespace std; int n, top; struct edge { int to, vis, id; //to代表边的终点,id代表边的编号 }; vector<edge>w[M]; string str[M]; //原来还可以这样定义字符串数组 int ans[M]; int fa[29]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } void fleury(int loc) { for (int i = 0; i<w[loc].size(); i++) if (!w[loc][i].vis) { w[loc][i].vis = 1; fleury(w[loc][i].to); ans[top++] = w[loc][i].id; } return; } int main() { int indegree[28], outdegree[28]; int T; scanf("%d", &T); while (T--) { top = 0; for (int i = 0; i<26; i++) { w[i].clear(); outdegree[i] = indegree[i] = 0; fa[i] = i; } scanf("%d", &n); int a, b; for (int i = 0; i<n; i++) cin >> str[i]; sort(str, str + n); //根据字典序排序 edge edg; int start; for (int i = 0; i<n; i++) { a = str[i][0] - ‘a‘; b = str[i][str[i].size() - 1] - ‘a‘; indegree[a]++; outdegree[b]++; fa[find(a)] = find(b); edg.to = b; edg.vis = 0; edg.id = i; w[a].push_back(edg); if (i == 0) //重要 起点必须为初始化为第一条边的出节点(字典序最小,且满足 欧拉回路 的的要求) start = a; } int ss = 0, num = 0, start_num = 0, end_num = 0; for (int i = 0; i<26; i++) { if ((indegree[i] || outdegree[i]) && find(i) == i) //find(i)==i是用来判断整个图是否连通的,因为图存在欧拉通路的条件之一就是必须是连通图 ss++; //结合下面的ss==1,来理解,因为如果整个图是连通的,ss就只会在当i为根节点的时候+1 if (indegree[i] != outdegree[i]) { if (outdegree[i] - indegree[i] == -1) start = i, start_num++; //这里和上面的初始化start的步骤不懂,做题的时候就是卡在了选取第一个出节点的步骤 else if (outdegree[i] - indegree[i] == 1) end_num++; num++; } } if ((num == 0 || (num == 2 && start_num == 1 && end_num == 1)) && ss == 1) //存在欧拉通路的条件 { fleury(start); //我对start的选取不是很理解 for (int i = top - 1; i >= 0; i--) //要使输出的单词按字典序输出 { if (i == 0) cout << str[ans[i]] << endl; else cout << str[ans[i]] << "."; } } else cout << "***" << endl; } return 0; }
2018-04-07