洛谷 1019.单词接龙

这道题用的搜索,也就是DFS,但是有一点难度,虽然说是对于搜索的知识点的考察,但是对于编程者的编程模拟能力和分析能力会有比较大的要求。

思路:首先我们审题,会注意到以下几点:

1.单词后面相同的部分和另一个单词前面相同的部分可以接在一块,并不是直接接上,而是重合的地方合并了;

2.每个单词还不止用一次,每个单词至多用2次。

那么,我们纯靠DFS肯定不会有什么效果的。DFS要搜索的话也是有目的的搜索的,但是上面的问题有很多,我们需要逐个处理完才能够比较明确的枚举。

我们想,如果说每个单词需要不多于2次使用,我们是不是需要记录每个单词使用的次数呢?这是一点,可以定义used数组进行记录每一个单词的使用次数,这里输入字符我们就用string,因为这样会很方便的知道多个字符串的序号是什么。

既然说是相同的部分不能重复接上,那么我们会想到一个string函数中的功能:substr,这个东西能够定义从某一个字符的位置开始,从后面连上它本身能够连接多少字符,这是个很方便的运用。我们就运用这个进行接上单词。

但是还有一个问题:我们需要怎么判断每个单词到底能不能连接呢?

这样就需要有一定的刷题经验了,我们可以用一个数组cnt[][]的二维数组表示第i个单词后面与第j个单词卡面重合的个数是多少,这样既能够记录这两个单词到底能不能接上,而且还能知道个数有多少个!这样就很方便了。

解决完上面这几个问题,还有一点需要知道:怎么接上单词才能达到最长呢?我们在接上单词的过程中,明显一个特点就是重合的字符少了,自然接上的单词长度就长了,这就是结论,当我们遍历的时候,一旦找到可以重合的单词就直接认定这就是最长的,也就是所谓的重合的越少越好。

预处理结束了,我们需要开始dfs搜索了,在我们搜索的时候需要遍历全部的单词,知道哪个单词的首位与所给出的字母相同,在这个单词的基础上进行搜索,dfs函数定义两个变量,一个就是单词接龙的第一个字符串,第二个变量就是对应的这个字符串在刚刚定义的编号是多少。

写DFS时,第一件事就是把这个将要接上单词的单词的使用个数+1,然后再去遍历其他单词,判断条件就是能否接上,这个能接上的单词使用次数超过2了没有,然后接上继续搜索。

上代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 30
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;

LL n, m, counts, num;
string s[MAX];
int cnt[MAX][MAX];
int used[MAX];
void dfs(string haha, int u) {
    used[u] ++;
    counts = max(counts, (LL)haha.size());
    for (int i = 0; i < n; i++) {
        if (cnt[u][i] && used[i] < 2) {
            dfs(haha + s[i].substr(cnt[u][i]), i);
        }
    }
    used[u]--;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> s[i];
    }
    char word;
    cin >> word;
    //下面的操作都是对于各个单词的预处理,也就是对于单词能不能接上的判断,能接上的话重合个数是多少进行处理操作。
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            string a = s[i];
            string b = s[j];
            for (int k = 1; k < min(a.size(), b.size()); k++) {
                if (a.substr(a.size() - k, k) == b.substr(0, k)) {
                    cnt[i][j] = k;
                    break;//重合的越少越好,这样才能保证接龙的数列是最长的长度.
                }
            }
        }
    }
    for (int i = 0; i < n; i++) {
        if (s[i][0] == word) {
            dfs(s[i], i);
        }
    }
    cout << counts << endl;
    return 0;
}
相关推荐
古月居GYH6 分钟前
在C++上实现反射用法
java·开发语言·c++
Betty’s Sweet9 分钟前
[C++]:IO流
c++·文件·fstream·sstream·iostream
敲上瘾23 分钟前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
福大大架构师每日一题25 分钟前
文心一言 VS 讯飞星火 VS chatgpt (396)-- 算法导论25.2 1题
算法·文心一言
不会写代码的ys29 分钟前
【类与对象】--对象之舞,类之华章,共绘C++之美
c++
兵哥工控32 分钟前
MFC工控项目实例三十二模拟量校正值添加修改删除
c++·mfc
EterNity_TiMe_40 分钟前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
长弓聊编程42 分钟前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
cherub.1 小时前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
机器学习之心1 小时前
一区北方苍鹰算法优化+创新改进Transformer!NGO-Transformer-LSTM多变量回归预测
算法·lstm·transformer·北方苍鹰算法优化·多变量回归预测·ngo-transformer