困难的串(Krypton Factor, UVa 129)- 回溯法习题

题目

  • 题目参考网址:https://vjudge.net/problem/UVA-129
  • 大意:
    如果一个字符串包含两个相邻的重复子串,则称它是“容易的串”,其他串称为“困难的
    串”。例如,BB、ABCDACABCAB、ABCDABCD都是容易的串,而D、DC、ABDAB、
    CBABCBA都是困难的串。
    输入正整数n和L,输出由前L个字符组成的、字典序第k小的困难的串。例如,当L=3
    时,前7个困难的串分别为A、AB、ABA、ABAC、ABACA、ABACAB、ABACABA。输入
    保证答案不超过80个字符。

知识点

  • 回溯法

思路

  • 这道题和之前题目不一样的地方是,这道题只要找到答案就会返回,而之前的题目都是遍历寻找所有可行解。
  • 难点在于如何判断复杂串,尽可能减少判断的次数,全排列枚举在数量大的时候难以计算
  • 聪明的办法是,每次只判断增加后的部分(即添加的最后一个字符) 是否导致当前的串存在容易的串。从头到尾,我们都保证上一次添加到尾部的字符没有导致存在“容易的串”,那么结束,必然该串不是“简单的串”。如何判断?每一次判断尾部起的偶数个串(见注释1),逐个判断左部是否与右部分相同,如存在不同,就不必进行判断(必然不是简单的串)。遍历完仍然都相等,说明存在了“容易的串”。
  • 有一个疑问是:30 3的解,为什么长度得到的是28???
  • 其他与常规回溯法思路一致
  • 实际题目要求输出更加复杂这里做了简化
  • 注释1:
    检查 ABCDEFG -> ABCDE (FG) -> ABC (DEFG) -> A (BCDEFG)

代码

# include <iostream>
# include <string>

using namespace std;
int n, l;

bool check(string ans) {  // 每次只判断增加后的部分是否导致存在容易的串
    int len = ans.length();
    for (int i = 1; 2 * i <= len; i++) {  //
        int start = len - 2 * i, start1 = len - i;  // 计算左部分与右部分的起始位置
        bool ok = false;
        for (int j = 0; j < i; j++) {  // 左部分与右部分逐个判断
            if (ans[start + j] != ans[start1 + j]) {
                ok = true;  break;
            }
        }
        if (ok) continue;  // ok = true,存在不相等的字符,说明该长度不可能存在“简易的串”,那么检查一个长度(2,4,6,8...2*i)
        return false;
    }
    return true;  // 检查完,所有偶数长度都不存在 -> true,是复杂的串
}

bool dfs(string ans = "") {
    if (!check(ans))  // 判断
        return false;  // 不满足条件,返回
    if (ans.length() == n) {  // 符合条件 & 长度为n
        cout << ans << endl;  // 实际题目要求输出更加复杂这里做了简化
        return true;
    }

    for (int i = 0; i < l; i++) {
        ans += char(65 + i);
        // 一个为true,即找到了一个结果,一个返回true,全部返回true,结束
        if (dfs(ans))   return true;  
        ans.pop_back();  // 状态恢复
    }
    // 特别注意,不然遍历完默认返回了true(但其实并没有找到,应该继续返回上层继续搜索),导致结果异常!
    return false;  
}

int main() {
    // 简单输入
    cin >> n >> l;
    dfs();
    return 0;
}

过程中遇到的问题 & 解决

  • dfs()最后一行切记注意返回false,查了半天!!!默认返回为true,但其实并没有找到,应该继续返回上层继续搜索!

测试

输入:

7 3
30 3

结果:✔️

ABACABA
ABACABCACBABCABACABCACBACABACB
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值