Shuffle‘m Up(模拟、dfs两种方法)

本文介绍了两种方法解决扑克洗牌问题,一种是模拟法,另一种是深度优先搜索(DFS)法。在给定的初始牌堆和洗牌规则下,程序需确定能否通过多次洗牌得到特定的组合。模拟法通过不断更新牌堆并检查结果,而DFS法使用递归搜索所有可能的洗牌组合。每种方法都考虑了无法得到目标组合的情况,并给出了相应的退出条件。文章提供了C++代码实现,并给出了样例输入和输出解析。
摘要由CSDN通过智能技术生成

题目描述

原题链接
原文翻译:
扑克玩家在牌桌上最常见的消遣就是洗牌。洗牌是通过从两堆扑克筹码S1和S2开始进行的,每一堆包含C个筹码。每个堆栈可能包含几个不同颜色的筹码。

实际的shuffle操作是在C = 5时将S1的芯片与S2的芯片交错,如下图所示:
在这里插入图片描述
单个合成堆栈S12包含2 * C芯片。S12的最底层芯片是S2的最底层芯片。在那个芯片的顶部,是S1最下面的芯片。交错过程继续从S2的底部取出第二个芯片,并将其放置在S12上,然后从S1的底部取出第二个芯片,以此类推,直到S1的顶部芯片被放置在S12上。

shuffle操作完成后,S12被分成两个新的栈,从S12中取出最底部的C芯片组成新的S1,从S12中取出最顶部的C芯片组成新的S2。然后重复洗牌操作,形成一个新的S12。

对于这个问题,您将编写一个程序来确定一个特定的合成堆栈S12是否可以通过对两个堆栈进行若干次洗牌来形成。

输入:
第一行输入包含一个单一的整数N(1≤N≤1000),这是接下来的数据集的数量。

每个数据集由四行输入组成。数据集的第一行指定一个整数C,(1≤C≤100),表示每个初始堆栈(S1和S2)中的芯片数量。每个数据集的第二行指定堆栈S1中每个C芯片的颜色,从最底部的芯片开始。每个数据集的第三行指定从最底部的芯片开始的堆栈S2中每个C芯片的颜色。颜色用单个大写字母(a到H)表示。芯片颜色之间没有空格或分隔符。每个数据集的第四行包含2 * C大写字母(A到H),表示对S1和S2进行零次或多次洗牌的期望结果的颜色。首先指定最底部芯片的颜色。

输出:
每个数据集的输出由一行组成,该行显示数据集编号(1到N)、一个空格和一个整数值(获得所需结果堆栈所需的最小洗牌次数)。如果数据集的输入不能得到想要的结果,则显示洗牌次数的值- 1(−1)。

简单概括题意
给出两个长度为len的字符串s1, s2和一个长度为2 * len的字符串s12, 每次先让s2先,s1后,先后去一个字符得到一个长度为 2 len的字符串s,如果发现得到的字符串s和s12相等就输出交换的次数,否则就让s的左半边等于右半边等于s2, 再进行上述变换,如果无法使百年换后的s == s12, 输出-1.

法一:模拟

思路:
我们用字符串、map(C++中的STL)
来完成。

  1. 这两个字符串形成的新串的个数是有限的,我们可以用while循环。当形成两个一样的字符串时我们就可以终止循环,输出-1了。
  2. substr函数的应用。
  3. 每组数据,记得把map clear()。
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
bool flag;
int len, ans, kase = 0;
int main(void){
    int t;
    cin >> t;
    map <string, bool> vis;
    while(t --){
        vis.clear();
        string s1, s2, s12;
        ans = 0;
        cin >> len;
        cin >> s1 >> s2 >> s12;
        while(true){
            flag = true;
            ans ++;
            string str;
            int i = 0;
            for(int j = 0; j < len; j ++){
                str += s2[i ++];
                str += s1[j];
            }
            if(vis[str] && str != s12){
                ans = -1;
                break;
            }
            vis[str] = true;
            if(str == s12) break;
            s1 = str.substr(0, str.size() / 2);
            s2 = str.substr(str.size() / 2, str.size());

        }
        cout << ++ kase << " " << ans << endl;
    }
    return 0;
}

法二:dfs

我们用dfs来实现这个过程也得考虑一个问题:当得不到目标字符串时,我们如何结束调用?我们可以用一个set(STL一种)。

#include <iostream>
#include <algorithm>
#include <set>
#include <string>
using namespace std;
set <string> se;
string s;
int len, ans;

void dfs(string s1, string s2, int n){
    string str;
    for(int i = 0; i < len; i ++){
        str.push_back(s2[i]);
        str.push_back(s1[i]);
    }
    if(se.count(str)) return;
    se.insert(str);
    if(str == s){
        ans = n;
        return;
    }
    else{
        s1.clear();
        s2.clear();
        for(int i = 0; i < len; i ++){
            s1.push_back(str[i]);
        }
        for(int i = len; i < len * 2; i ++){
            s2.push_back(str[i]);
        }
        dfs(s1, s2, n + 1);
    }
}

int main(void){
    string s1, s2;
    int t;
    cin >> t;
    for(int i = 1; i <= t; i ++){
        se.clear();
        scanf("%d", &len);
        cin >> s1 >> s2 >> s;
        ans = -1;
        dfs(s1, s2, 0);
        if(ans > 0) ans ++;//我们ans从0开始算来着。记得加1表示第几个。
        cout << i << " " << ans << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xuhx&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值