洛谷 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;
}
相关推荐
以卿a14 分钟前
C++ 模板初阶
开发语言·c++
计算机小白一个5 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
万事可爱^6 小时前
HDBSCAN:密度自适应的层次聚类算法解析与实践
算法·机器学习·数据挖掘·聚类·hdbscan
黑不溜秋的6 小时前
C++ 设计模式 - 策略模式
c++·设计模式·策略模式
大数据追光猿8 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Dream it possible!8 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
夏末秋也凉8 小时前
力扣-回溯-46 全排列
数据结构·算法·leetcode
南宫生8 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴8 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
Leuanghing8 小时前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode