洛谷 P1019 单词接龙 题解

肺炎时节家家闭,提交OJ处处WA

到处都是坑

以下部分“前者”代指目前的龙,“后者”代指现在正在判断的单词

  • 重叠的部分越小越好,这样接的龙才长(就是贪心,一开始贪反了。。。)

  • “相邻的两部分不能存在包含关系”其实在一些情况下是可以的,比如两者相同且首尾字母相同时:tact->tact,或者是前者的最后一字母和后者的第一个字母相同时:superbus->super

  • 记得同一个单词最多只能接两遍,dfs后记得–vis[i],也就是回溯

  • 前者包含后者或者后者包含前者都是可以的,因为是“相邻的两部分不能……”(当然你要判断相邻的两部分不能存在包含关系)

  • 后者长度为1时直接跳过,因为对答案不可能有贡献

附代码:

#include
using namespace std;
int n;
string s[27];
int vis[27];
int maxn_len;
int max(int x,int y){
    if(x>y)return x;
    else return y;
}//手写更快
void dfs(string x){
    maxn_len=max(maxn_len,x.size());//每次都取一遍大的
    for(int i=1;i<=n;++i){
        if(s[i].size()==1)continue;//跳过
        if(vis[i]>=2)continue;//来过两遍了
        int pre=1,minn=min(x.size(),s[i].size());bool flag=false;
        for(int j=1;j<=minn;++j){//枚举长度
            if(x.substr(x.size()-j,j)==s[i].substr(0,j)){//提取子串
                pre=j;flag=true;break;//贪心,即刻退出
            }
        }
        if(!flag)continue;//一次都没找到过
        //不加你会找错的,不然就是把pre的初值设为不可能取到的数,然后判断pre的值是否有改变
        --pre;//下面用的是下标,所以要--
        ++vis[i];//来过一次了
        string nx=x+s[i].substr(pre+1,s[i].size()-pre-1);//接龙
        dfs(nx);
        --vis[i];//记得回溯
    }
    return;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;++i)cin>>s[i];
    string sta;//必须用string,因为dfs里肯定是string(不然你搜完一遍后因为类型不同就结束了)
    cin>>sta;
    dfs(sta);
    cout<<maxn_len;
	return 0;
}

你可能感兴趣的:(深搜,字符串,贪心)