3.28 OJ

单词接龙

作者: Turbo

时间限制: 1s

章节: 深度优先搜索

问题描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外,相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。

例输入

5

at

touch

cheat

choose

tact

a

样例输出

23

样例说明

连成的"龙"为atoucheatactactouchoose

cpp 复制代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;

const int N = 25;
int n;
char start;
string word[N];
int g[N][N];  // g[i][j]表示word[i]和word[j]的最小重叠长度
int used[N];  // 记录每个单词的使用次数
int ans;

void dfs(string dragon, int last)
{
    // 更新最长龙的长度
    ans = max(ans, (int)dragon.size());
    
    // 标记当前单词使用次数+1
    used[last]++;
    
    // 尝试所有可能的接龙单词
    for(int i = 0; i < n; i++)
    {
        // 如果有重叠部分且使用次数少于2次
        if(g[last][i] > 0 && used[i] < 2)
        {
            // 拼接:当前龙 + 单词i去掉重叠部分
            dfs(dragon + word[i].substr(g[last][i]), i);
        }
    }
    
    // 回溯
    used[last]--;
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++) 
        cin >> word[i];
    cin >> start;
    
    // 预处理任意两个单词之间的重叠长度
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            string a = word[i], b = word[j];
            g[i][j] = 0;  // 初始化为0表示不能连接
            
            // 寻找最小重叠长度(至少重叠1个字符,不能完全包含)
            for(int k = 1; k <= min(a.size(), b.size()) - 1; k++)
            {
                // 检查a的后k个字符是否等于b的前k个字符
                if(a.substr(a.size() - k) == b.substr(0, k))
                {
                    g[i][j] = k;
                    break;  // 找到最小重叠长度就退出
                }
            }
        }
    }
    
    // 从以start开头的单词开始DFS
    for(int i = 0; i < n; i++)
    {
        if(word[i][0] == start)
        {
            dfs(word[i], i);
        }
    }
    
    cout << ans << endl;
    return 0;
    //总结:1.在二维数组中存两个单词之间的最小重叠长度 2.开始递归 递归首先更新长度 和使用次数 3.满足条件的单词进行拼接
}

总结:1.在二维数组中存两个单词之间的最小重叠长度 2.开始递归 递归首先更新长度 和使用次数 3.满足条件的单词进行拼接

排列问题

作者: Turbo

时间限制: 1s

章节: 深度优先搜索

问题描述

求一个0~N-1的排列(即每个数只能出现一次),给出限制条件(一张N*N的表,第i行第j列的1或0,表示为j这个数能不能出现在i这个数后面,并保证表中的第i行第i列为0,i和j都从0开始),将这个排列看成一个自然数,求从小到大排序第K个排列。

样例输入

3 2

0 1 1

1 0 0

0 1 0

样例输出

1 0 2

解释:

对于N=3的没有任何限制的排列如下:

第一:0 1 2

第二:0 2 1

第三:1 0 2

第四:1 2 0

第五:2 0 1

第六:2 1 0

根据题目所给的限制条件由于2不能出现在1后面,0不能出现在2后面

第一:0 2 1

第二:1 0 2

第三:2 1 0

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int limit[15][15];  // 限制条件矩阵
int number[15];     // 存储当前排列
int occupy[15];     // 标记数字是否已被使用
int N, K, cnt = 0;  // N:数字个数(0~N-1), K:目标序号, cnt:已找到的合法排列数
int found = 0;      // 标记是否已找到第K个排列

// 判断数字n能否放在位置pos上
// pos:当前位置, n:要放置的数字
int judge(int pos, int n)  
{
    if(pos == 0) return 1;  // 第一个数字没有前置限制
    if(!limit[number[pos-1]][n])  // 检查前一个数字与当前数字的限制
        return 0;
    return 1;
}

// 深度优先搜索生成排列
// depth:当前已放置的数字个数(即下一个要放置的位置)
void calAllSort(int depth)
{
    if(found) return;  // 已找到第K个,停止搜索
    
    if(depth == N)  // 已经放置完所有数字
    {
        cnt++;
        if(cnt == K)  // 是第K个排列
        {
            for(int i = 0; i < N; i++)
                if(i==0) 
                {
                    cout<<number[i];
                }else
                {
                    cout<<" "<<number[i];
                }
            printf("\n");
            found = 1;  // 标记已找到
        }
        return;
    }
    
    // 按数字从小到大尝试,保证字典序
    for(int i = 0; i < N; i++)
    {
        if(found) return;  // 已找到,停止搜索
        
        // 数字未使用且满足限制条件
        if(occupy[i] == 0 && judge(depth, i))
        {
            number[depth] = i;  // 放置数字
            occupy[i] = 1;      // 标记已使用
            calAllSort(depth + 1);  // 递归下一层
            occupy[i] = 0;      // 回溯
        }
    }
}

int main()
{
    // 初始化
    memset(occupy, 0, sizeof(occupy));
    memset(limit, 0, sizeof(limit));
    
    // 输入N和K
    scanf("%d%d", &N, &K);
    
    // 输入限制条件矩阵
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < N; j++)
        {
            scanf("%d", &limit[i][j]);
        }
    }
    
    // 开始搜索
    calAllSort(0);
    //总结:在dfs中遍历每一个组合 1.检查该数字能不能添加(未被使用且前一个数字的限制矩阵中这个数的位置为1)2.添加后number记录 depth++
    return 0;
}

总结:在dfs中遍历每一个组合 1.检查该数字能不能添加(未被使用且前一个数字的限制矩阵中这个数的位置为1)2.添加后number记录 depth++

和为T

作者: Turbo

时间限制: 1s

章节: 深度优先搜索

问题描述

从一个大小为n的整数集中选取一些元素,使得它们的和等于给定的值T。每个元素限选一次,不能一个都不选。

输入说明

第一行一个正整数n,表示整数集内元素的个数。

第二行n个整数,用空格隔开。

第三行一个整数T,表示要达到的和。

1<=n<=22

T<=maxlongint

集合中任意元素的和都不超过long的范围

cpp 复制代码
#include <iostream>
using namespace std;

const int MAXN = 25;

int n;              // 元素个数
int a[MAXN];        // 存储输入的数字
int T;              // 目标和
int path[MAXN];     // 存储当前选择的元素(下标)
int len = 0;        // 当前选择个数
int total = 0;      // 总方案数

// 深度优先搜索
// pos: 当前考虑的元素下标(从1到n)
// sum: 当前已选元素的和
void dfs(int pos, int sum) {
    if (pos > n) {
        // 已经考虑完所有元素
        if (sum == T && len > 0) {  // 不能一个都不选
            total++;
            // 输出当前解
            for (int i = 0; i < len; i++) {
                //if (i > 0) cout << " ";
                cout << a[path[i]]<<" ";
            }
            cout << endl;
        }
        return;
    }
    
    // 关键:先搜索不选的情况,再搜索选的情况
    // 这样能保证优先输出不包含后面元素的解
    
    // 情况1:不选当前元素
    dfs(pos + 1, sum);
    
    // 情况2:选当前元素
    path[len++] = pos;      // 记录选中的元素下标
    dfs(pos + 1, sum + a[pos]);
    len--;                  // 回溯
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    cin >> T;
    
    dfs(1, 0);
    cout << total << endl;
    //总结:另一种递归思想 不是全排列 而是对于单个元素位置选择选或不选 
    return 0;
}

/总结:另一种递归思想 不是全排列 而是对于单个元素位置选择选或不选

Reinforcement learning is a powerful approach for solving sequential decision-making problems. In this framework, an agent interacts with an environment by taking actions and receiving rewards. The goal is to learn an optimal policy that maximizes cumulative rewards over time. Unlike supervised learning, reinforcement learning relies on trial-and-error rather than labeled data. Techniques such as Q-learning and policy gradient methods are widely used to train agents. With the integration of deep neural networks, deep reinforcement learning has achieved remarkable success in complex tasks such as game playing, robotic control, and autonomous systems. However, challenges such as sample inefficiency and unstable training remain key issues that researchers are actively addressing.

强化学习是解决序列决策问题的有力方法。在此框架中,智能体通过采取行动并接收奖励来与环境进行交互。目标是学习一种能够随时间累积奖励最大化的最优策略。与监督学习不同,强化学习依赖试错而非标注数据。Q学习和策略梯度等方法被广泛用于训练智能体。随着深度神经网络的融合,深度强化学习在游戏博弈、机器人控制和自主系统等复杂任务中取得了显著成功。然而,样本效率低下和训练不稳定等挑战仍是研究人员积极解决的关键问题。

相关推荐
AI成长日志2 小时前
【笔面试算法学习专栏】堆与优先队列专题:数组中的第K个最大元素与前K个高频元素
学习·算法·面试
雅俗共赏1003 小时前
医学图像重建中常用的正则化分类
算法
IronMurphy3 小时前
【算法三十二】
算法
Mr_Xuhhh3 小时前
LeetCode 热题 100 刷题笔记:高频面试题详解(215 & 347)
算法·leetcode·排序算法
mmz12073 小时前
贪心算法3(c++)
c++·算法·贪心算法
j_xxx404_3 小时前
蓝桥杯基础--排序模板合集II(快速,归并,桶排序)
数据结构·c++·算法·蓝桥杯·排序算法
月落归舟3 小时前
排序算法---(四)
算法·排序算法
童话ing3 小时前
【LeetCode】239.滑动窗口最大值
数据结构·算法·leetcode·golang
计算机安禾3 小时前
【数据结构与算法】第13篇:栈(三):中缀表达式转后缀表达式及计算
c语言·开发语言·数据结构·c++·算法·链表