欧拉回路学习

题目链接
欧拉回路解决

#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");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值