P1019 单词接龙题解

题目传送门

C++代码

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 30;
string a[N * 2];
int res; //最大长度
char start;  //起始字符
bool st[N * 2];//是否已经使用过
int n;

//两个字符串,最小重叠部分的长度
string merge(string a, string b) {
    int n = INF;
    //相连接 两层循环找出a的所有可能后缀,然后与b串的前缀进行对比,找到最长的
    for (int i = a.size() - 1; i >= 0; i--) { //从后向前,注意起始范围
        //i=a.size()-1 i参数准备用于 a.substr(i),就是取后缀,这样就表示取最后一个字符。
        string t = a.substr(i);//从i处开始截取,一直截取到结束的意思,即后缀
        //这个b.compare用的漂亮,可以避开了b.substr(0,t.size())时超出b的范围的问题。
        /*  compare
            两个字符串相同,返回0。
            a字符串小于b字符串,返回-1。
            a字符串大于b字符串,返回1。
         */
        if (b.compare(0, t.size(), t) == 0) {
            n = a.size() - i;
            break;
        }
    }
    if (n < INF) return a + b.substr(n);
    else return "";
}

//深度优先搜索
//参数1:想要接第几个
//参数2:完成拼接的字符串
void dfs(int step, string tmp) {
    //不要求一定要全部使用完,所以随时需要更新结果
    if (tmp.size() > res) res = tmp.size();
    //如果没有可以尝试的了,需要返回
    if (step == 2 * n + 1)return;
    //所有的情况尝试一遍
    for (int i = 1; i <= 2 * n; i++) {
        if (!st[i]) {
            string ans = merge(tmp, a[i]);
            //找以start为开始字符,并且没有使用过的字符串
            if (ans.size()) {
                st[i] = true;
                dfs(step + 1, ans);
                st[i] = false;
            }
        }
    }
}

int main() {
    //输入
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    //复制了一份,因为一个字符串最多出现两次
    for (int i = n + 1; i <= 2 * n; i++) a[i] = a[i - n];
    //龙的开始字符
    cin >> start;

    //遍历所有以start开头的字符串
    for (int i = 1; i <= n; i++)
        if (a[i][0] == start) {
            st[i] = true;
            dfs(1, a[i]);
            st[i] = false;
        }
    //输出最大长度
    cout << res << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/littlehb/p/15069071.html