算法竞赛备考冲刺必刷题(C++) | 洛谷 CF25E Test

本文分享的必刷题目是从蓝桥云课洛谷AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。

欢迎大家订阅我的专栏:算法题解:C++与Python实现!

附上汇总贴:算法竞赛备考冲刺必刷题(C++) | 汇总


【题目来源】

洛谷:CF25E Test - 洛谷

【题目描述】

给定 3 3 3个字符串 s 1 , s 2 , s 3 s_1,s_2,s_3 s1,s2,s3,试求一个字符串,使 s 1 , s 2 , s 3 s_1,s_2,s_3 s1,s2,s3都是这个字符串的子串,并使这个字符串最短。输出最短字符串的长度 l l l。$ s_1,s_2,s_3长度\le100000$

【输入】

There are exactly 3 3 3 lines in the input data. The i i i -th line contains string s i s_i si . All the strings are non-empty, consists of lowercase Latin letters, the length of each string doesn’t exceed 10 5 10^5 105 .

【输出】

Output one number — what is minimal length of the string, containing s 1 s_1 s1 , s 2 s_2 s2 and s 3 s_3 s3 as substrings.

【输入样例】

ab
bc
cd

【输出样例】

4

【算法标签】

《洛谷 CF25E Test》 #字符串# #枚举# #KMP#

【代码详解】

#include 
using namespace std;

// 全局变量声明
int a[4][100005];       // KMP算法的next数组,a[i]对应第i个字符串
string s[4];            // 存储3个输入字符串
int ans = 1e9;          // 存储最短合并长度,初始化为极大值

/**
 * 计算KMP算法的next数组
 * @param x 当前处理的字符串索引(1-3)
 */
void getnext(int x)
{
    int m = s[x].size() - 1;  // 字符串实际长度
    for (int i = 2, j = 0; i <= m; i++)
    {
        while (j && s[x][i] != s[x][j + 1])
        {
            j = a[x][j];      // 回溯
        }
        if (s[x][i] == s[x][j + 1])
        {
            j++;
        }
        a[x][i] = j;          // 记录next值
    }
}

/**
 * 使用KMP算法计算两个字符串合并后的最短长度
 * @param x 主字符串
 * @param y 模式字符串
 * @param id 模式字符串的索引(用于获取next数组)
 * @return 合并后的最短长度
 */
int getkmp(string x, string y, int id)
{
    int n = x.size() - 1;     // 主字符串长度
    int m = y.size() - 1;     // 模式字符串长度
    int j = 0;
    for (int i = 1; i <= n; i++)
    {
        while (j && x[i] != y[j + 1])
        {
            j = a[id][j];     // 回溯
        }
        if (x[i] == y[j + 1])
        {
            j++;
        }
        if (j == m)           // 完全匹配
        {
            return n;          // 返回主字符串长度(可以完全包含模式串)
        }
    }
    return n + m - j;         // 返回合并后的长度
}

int main()
{
    // 输入3个字符串并预处理
    for (int i = 1; i <= 3; i++)
    {
        cin >> s[i];
        s[i] = '0' + s[i];    // 添加前缀方便索引
        getnext(i);           // 计算next数组
    }
    
    // 枚举所有排列组合情况(3!种)
    for (int i = 1; i <= 3; i++)
    {
        for (int j = 1; j <= 3; j++)
        {
            for (int k = 1; k <= 3; k++)
            {
                // 跳过重复的字符串
                if (i == j || i == k || j == k)
                {
                    continue;
                }
                
                // 计算前两个字符串合并后的最短长度
                int len1 = getkmp(s[i], s[j], j);
                int coinlen = s[i].size() + s[j].size() - len1 - 1;
                
                // 构造合并后的字符串
                string t1 = s[j].substr(1, s[j].size() - 1);
                string t2 = s[i] + t1.substr(coinlen - 1, t1.size() - coinlen + 1);
                
                // 计算三个字符串合并后的最短长度
                len1 = getkmp(t2, s[k], k);
                
                // 更新全局最小值
                ans = min(ans, len1);
            }
        }
    }
    
    // 输出结果
    cout << ans;
    return 0;
}

【运行结果】

ab
bc
cd
4

你可能感兴趣的:(c++,算法,开发语言)