【题解】 小狗

题目描述

【题目描述】
    小 Q 是个爱狗狂魔,他饲养了 N(N<=2000)条中华田园犬狗和 M(M<=2000)条秋田犬。
    并且给每条狗取了一个英文名字,例如:Sally,Sussan,Lysa 等,
    为了方便起见,小 Q 登记时只会登记首字母,例如 Sally、Sussan、Lysa 只会登记为 S、S、L。
    现在中华田园犬和秋田犬分别从左至右各站成了一队。小 Q 准备带他们出去踏青了!
    但因为踏青的路实在太窄,小 Q 不得不在踏青前把两条队伍合成一队。
    那如何合呢?我们假设中华秋田犬所在的队伍为 A 队,秋田犬所在队伍为 B。
    最后合成的新队伍为 C。大家知道的如果从队伍中间选择小狗加入新队伍,容易使原队伍混乱.
    所以现在我们制定如下规则:
        (1)每次从 A 队或者 B 队的头或者尾选取一条小狗加入到新的队伍 C 的尾部去(第一条选择的小狗为头)。
        (2)重复(1)的操作,直到 A 队和 B 队的所有小狗都站到 C 队为止。
    现在小 Q 想知道,按照这种规则,他登记的新队列的最小字典序为多大?
【输入格式】
    第 1 行:两个整数 N 和 M.
    第 2 行至第 N+1 行:每行一个大写字母,表示 A 队中小狗的头字母.
    第 N+2 至 N+1+M 行:每行一个大写字母,表示 B 队中小狗的头字母.
【输出格式】
    一行,得到的最小字典序的序列.
【样例输入】
    3 3
    A
    C
    D
    B
    C
    B
【样例输出】
    ABBCCD
【数据说明】
    50%数据 1<=n,m<=100
    100%数据 1<=n,m<=2000

题目大意

给定2个字符串(有且仅有大写字母组成),每次将任意一个字符串的头部或尾部加入新字符串,求新字符串最小字典序。

思路

设一个字符串为 \(s_1\),另一个字符串为 \(s_2\)
由于要字典序最小,所以要在 \(s_1\) 的头部、尾部,\(s_2\) 的头部、尾部中找最小的字符加入。

但是,如果其中最小的字符有两个,又该选哪个呢?这时就应该往它们的下一个去看,但是这样一直往后找,就会太复杂。

所以可以给每个字符串建一个反字符串进行比较。例如:原字符串 \(s_1\)\(CBAC\),那么就可以建一个反字符串 \(rs_1\)\(CABC\),因为 \(s_1 < rs_1\),所以选尾部的 \(c\) 显然更优。

但是如果这2个字符串长度不同,就会发生错误。举个例子,字符串 \(s_1\)\(AB\)\(s_2\)\(ABB\)。如果此时按字典序进行比较,则有 \(s1 < s2\),但是先选择 \(s_1\) 显然更优。这时可以比较 $s_1 + s_2 $ 和 \(s_2 + s_1\),就可以实现。

代码

#include <bits/stdc++.h>
using namespace std;

int n, m;
char a[2005], b[2005];
string tmp[6];

int FindMin(int as, int ae, int bs, int be)
{
    tmp[1] = tmp[2] = tmp[3] = tmp[4] = "";
    // tmp[1] 是 字符串a,tmp[2] 是 字符串a的翻转 
    // tmp[3] 是 字符串b,tmp[4] 是 字符串b的翻转  

    for (int i = as, j = ae; i <= ae; i ++ , j -- )
        tmp[1] += a[i], tmp[2] += a[j];
    for (int i = bs, j = be; i <= be; i ++ , j -- )
        tmp[3] += b[i], tmp[4] += b[j];

    int t1 = 1, t2 = 3;
    if (tmp[2] < tmp[1]) t1 = 2; // 相同长度直接比较 
    if (tmp[4] < tmp[3]) t2 = 4; // 相同长度直接比较 

    // 不同长度拼接比较
    if (tmp[t2] == "" || tmp[t1] + tmp[t2] < tmp[t2] + tmp[t1]) return t1;  
    else return t2;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    for (int i = 1; i <= m; i ++ ) cin >> b[i];

    int as = 1, ae = n, bs = 1, be = m; // as、ae 分别是 a 的起始和结束 , bs、be 分别是 b 的起始和结束
    string ans = "";
    for (int i = 1; i <= n + m; i ++ )
    {
        int ret = FindMin(as, ae, bs, be); // 找出选哪边

        // 1 表示 选a的头部,2 表示 选a的尾部 ,3 表示 选b的头部,4 表示 选b的尾部 
        if (ret == 1) ans += a[as ++ ];
        else if (ret == 2) ans += a[ae -- ];
        else if (ret == 3) ans += b[bs ++ ];
        else ans += b[be -- ];
    }

    cout << ans << '\n';

    return 0;
}
posted @ 2024-08-12 19:12  T_泓  阅读(27)  评论(0编辑  收藏  举报