洛谷 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;
}
相关推荐
Charles Ray36 分钟前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码36 分钟前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
limingade3 小时前
手机实时提取SIM卡打电话的信令和声音-新的篇章(一、可行的方案探讨)
物联网·算法·智能手机·数据分析·信息与通信
jiao000015 小时前
数据结构——队列
c语言·数据结构·算法
迷迭所归处6 小时前
C++ —— 关于vector
开发语言·c++·算法
leon6257 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林7 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z7 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
Aic山鱼7 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法
white__ice8 小时前
2024.9.19
c++