Silly_3kidZ

思至水穷处,码看云起时

DFS-单词接龙题解

题解

1117. 单词接龙 - AcWing题库

题意:

给定\(n(n\leq20)\)个单词以及单个字符作为开头字母,求出以这个字母开头的最长的“单词接龙”的长度,每个单词最多使用两次

思路:

\(n\leq20\),根据由数据范围反推算法复杂度以及算法内容 - AcWing结合题意,很显然用dfs算法解决,结合dfs模板敲代码即可

ans
void dfs(层数,其他参数){
    if(出局判断){ // 到达最底层,或者满足条件推出
        更新答案 // 答案一般用全局变量表示
        return; // 返回到上一层
    }
    (剪枝) // 在进一步dfs之前剪枝
    for(枚举下一层可能的情况){
        if(used[i]==0){ // 如果状态i没有用过,就可以进入下一层
            used[i]=1; // 标记状态i已经使用过
            dfs(层数+1,其他参数); // 下一层
            used[i]=0; // 回溯
        }
    }
    return; // 返回到上一层
}

code:

#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr << #x << " = " << x << "\n";
int n;
const int N = 25;
string g[N];
map<string,int> cnt;
//
int check(string s1,string s2){
    int len1=s1.size(),len2=s2.size();
    int len = min(len1,len2);
    int res=0;
//    debug(s1);debug(s2);
//    debug(len1);debug(len2);
    for(int i=1;i<len;i++){
//        debug(i);
//        debug(s1.substr(len1-i,i));
//        debug(s2.substr(0,i));
        if(s1.substr(len1-i,i)==s2.substr(0,i)){
            res=i;
            break;
        }
    }
    return res;
}
int dfs(string s,int len){
    cnt[s]++;
//    debug(len);
    if(cnt[s]>2){
        return len;
    }
    int res=len;
    for(int i=0;i<n;i++){
//        int ii=i;debug(ii);
        int sz = check(s,g[i]);
        if(cnt[g[i]]<2 && sz>0){
            res = max(res,dfs(g[i],len+g[i].size()-sz));
//            debug(res);
            cnt[g[i]]--;
        }
    }
    return res;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>g[i];
        cnt[g[i]]=0;
    }
    char ch;
    cin>>ch;
    int ans =0;
    for(int i=0;i<n;i++){
        if(g[i][0]==ch){
            ans = max(ans,dfs(g[i],g[i].size()));
            cnt[g[i]]--;
        }
//        debug(cnt[g[0]]);
//        debug(cnt[g[1]]);
    }
    cout << ans << "\n";
    return 0;
}

收获

bug1:

对于

2
at
touch
a

输入样例

为什么第31行res = 0得出的结果是0, res = len得出的结果是6,同样在里面都取了max,为什么结果会不同呢?

因为最后可能字符串s和其他的字符串都没连接上啊,那么最后要返回的就是连接到字符串s为止的字符串长度,你取0了可能最后返回的都是0,当然结果就是0了。

bug2

代码53-57行

for(int i=0;i<n;i++){
    if(g[i][0]==ch){
        ans = max(ans,dfs(g[i],g[i].size()));
        cnt[g[i]]--;
    }

有回溯的dfs结束后除初始状态,其他所有状态都会归零,对于初始状态要额外操作使其初始化,防止对以其它字符串为开头的dfs产生影响。

优化

  1. 求的是最大长度,我们不需要用带有int返回值的dfs,直接在每次dfs后不管是否连接到极限都更新ans = max(ans,已连接的字符串长度),这样只需无脑照板子void dfs()抄即可,不用花时间考虑int dfs()
  2. 预处理出每两个字符串之间可连接的最少长度,dfs加一个参数-当前所使用的字符串的序号,以便快速判断出两个字符串之间连接的最少长度。这样可以优化时间复杂度

优化代码AcWing 1117. 单词接龙 - AcWing

posted @ 2024-03-07 23:50  Silly_3kidZ  阅读(53)  评论(0)    收藏  举报