题目链接
欧拉回路解决
#include <iostream>
#include <string>
#include <string.h>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
vector<string> dictionary; //用来存储字符串
vector<string> trace;
int num; //表示字符串的个数
const int alphanum = 26;
int visit[1000];
int indegree[alphanum];
int outdegree[alphanum];
int father[alphanum];
void initset(){
for (int i = 0; i < alphanum; ++i) {
father[i] = i;
}
}
int root(int a){
return a==father[a]?a:father[a]=root(father[a]);
}
void connect(int a, int b){
if (root(a) != root(b)){
int fa = root(a);
int fb = root(b);
father[fa] = fb;
}
}
int Euler(){
//找出起点
int s ,e;
s = e = 0;
int start = 0;
for (int i = 0; i < alphanum; ++i) {
if (visit[i]){
int temp = indegree[i]-outdegree[i];
if (temp == 1) e++;
if (temp == -1){
s++;
start = i;
}
if (abs(temp)>1) return -1;
}
}
if (s==1&&e==1||s+e==0){
return start;
}
return -1;
}
void dfs(char a, int cnt ){
//首先找到以a开头的字符串
if (cnt == num){
throw "ok";
}
int i = 0;
//二分查找查到开始以a开通的字符
int first = 0,end = num-1, mid;
while (first<=end){
mid=(first+end)/2;
char temp = dictionary[mid][0];
if (temp == a){
i = mid;
break;
} else if (temp>a){
end = mid-1;
} else{
first = mid+1;
}
}
//一定会选出来
//找到第一个开始便利
while(i>=0&&dictionary[i][0]==a)
i--;
for (i++; dictionary[i][0] == a; ++i) {
if (!visit[i]){
visit[i] = 1;
trace.push_back(dictionary[i]);
int len = dictionary[i].size();
dfs(dictionary[i][len-1], cnt+1);
visit[i] = 0;
trace.pop_back();
}
}
}
int main(){
// freopen("../in.txt", "r", stdin);
int testcase;
scanf("%d", &testcase);
while (testcase--){
trace.clear();
dictionary.clear();
memset(visit, 0, sizeof(visit));
memset(indegree,0, sizeof(indegree));
memset(outdegree,0, sizeof(outdegree));
initset();
scanf("%d", &num);
string temp;
for (int i = 0; i < num; ++i) {
cin>>temp;
dictionary.push_back(temp);
int a = temp[0]-'a';
int b = temp[temp.length()-1]-'a';
indegree[b]++;
outdegree[a]++;
visit[a] = 1;
visit[b] = 1;
connect(a,b);
}
// 检查是否是联通的
int index = -1;
for (int i = 0; i < alphanum; ++i) {
if (visit[i]){
index = root(i);
break;
}
}
bool iscon = true;
for (int i = 0; i < alphanum; ++i) {
if (visit[i]&&root(i)!=index){
iscon = false;
break;
}
}
if (!iscon) {
cout<<"***"<<endl;
continue;
}
//遍历欧拉图
int start = Euler();
if (start == -1){
cout<<"***"<<endl;
continue;
}
//寻找最适合的组合,dfs,因为满足欧拉图,一定存在这样的组合,用首字母去找
memset(visit,0, sizeof(visit));
sort(dictionary.begin(),dictionary.end());
try {
dfs(start+'a', 0);
}catch (...){
cout<<trace[0];
for (int i = 1; i < trace.size(); ++i) {
cout<<"."<<trace[i];
}
cout<<endl;
}
}
}
DFA是超时的。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> dictionary;
vector<string> trace;
int visit[1000];
char temp[30];
int num;
bool flag;
string res = "";
bool isok(){
for (int i = 0; i < num; ++i) {
if (!visit[i]) return false;
}
return true;
}
void dfs(string s){
//检查是否满足条件
if (isok()) {
flag = true;
string temp;
temp.append(dictionary[0]);
for (int i = 1; i < dictionary.size(); ++i) {
temp.append(".");
temp.append(dictionary[i]);
}
if (res.empty()|temp<res)
res = temp;
return;
}
for (int i = 0; i < num; ++i) {
if (!visit[i]&&dictionary[i][0]==s[s.length()-1]){
visit[i] = 1;
trace.push_back(dictionary[i]);
dfs(dictionary[i]);
visit[i] = 0;
trace.pop_back();
}
}
return;
}
int main(){
// freopen("../in.txt","r",stdin);
int testcase;
scanf("%d", &testcase);
while (testcase--){
memset(visit, 0, sizeof(visit));
dictionary.clear();
scanf("%d", &num);
for (int i = 0; i < num; ++i) {
scanf("%s", temp);
dictionary.push_back(string(temp));
}
flag = false;
res = "";
for (int i = 0; i < num; ++i) {
visit[i] = 1;
trace.push_back(dictionary[i]);
dfs(dictionary[i]);
visit[i] = 0;
trace.pop_back();
}
if (flag) cout<<res<<endl;
else printf("***\n");
}
}