有这么一款单人卡牌游戏,牌面由颜色和数字组成,颜色为红、黄、蓝、绿中的一种,数字为0-10
中的一个。
游戏开始时玩家从手牌中选取一张卡牌打出,接下来如果玩家手中有和他上一次打出的手牌颜色或者数字相同的手牌,他可以继续将该手牌打出,直至手牌打光或者没有符合条件可以继续打出的手牌。
现给定一副手牌,请找到最优的出牌策略,使打出的手牌最多。
输入为两行,第一行是每张手牌的数字,数字由空格分隔,第二张为对应的每张手牌的颜色,
用r y b g
这4
个字母分别代表4
种颜色,字母也由空格分隔。手牌数量不超过10
。
输出一个数字,即最多能打出的手牌的数量。
1 4 3 4 5
r y b b r
3
如果打出1r
,那么下面只能再打出5r
,共打出两张牌,而按照4y-4b-3b
的顺序则可以打出三张牌,故输出3
1 2 3 4
r y b g
1
没有能够连续出牌的组合,只能在开始时打出一张手牌,故输出1
数据量很小,考虑直接回溯穷举的方案列出最长能够打出的连续手牌。
# 题目:2023C-最长连续手牌
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:回溯
# 代码看不懂的地方,请直接在群上提问
# 输入数字
nums = input().split()
# 输入颜色
colors = input().split()
# 获得手牌数量
n = len(colors)
# 构建长度为n的检查数组,查看每张手牌是否用过
used = [False] * n
ans = 0
# 构建回溯函数,各个参数的含义为
# cur_color: 当前所选择的手牌颜色
# cur_num: 当前所选择的手牌数字
# path_len: 当前已经连上的手牌数目,即路径长度
# n: 所有手牌数目
# colors,nums: 初始的颜色、数字数组
# used: 大小为n的一维数组,用于检查某张牌是否已经使用过
def dfs(cur_color, cur_num, path_len, n, colors, nums, used):
# 设置全局变量ans
global ans
# 更新ans
ans = max(path_len, ans)
# 横向遍历,考虑所有手牌
for i in range(n):
# 如果第i张牌已经使用过,则直接跳过
if used[i]:
continue
# 如果当前考虑的第i张牌的颜色或数字和当前牌一致,可以进行回溯
if cur_color == colors[i] or cur_num == nums[i]:
# 状态更新,标记第i张牌已经适用
used[i] = True
# 回溯
dfs(colors[i], nums[i], path_len + 1, n, colors, nums, used)
# 回滚
used[i] = False
return
# 遍历每一张手牌,作为起始手牌
for i in range(n):
# 先标记第i张牌使用过
used[i] = True
# 递归入口,以第i张牌为第一张牌,此时路径长度为1
dfs(colors[i], nums[i], 1, n, colors, nums, used)
# 类似回滚,标记第i张牌没用过
used[i] = False
print(ans)
import java.util.Scanner;
public class Main {
static int ans = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] nums = scanner.nextLine().split(" ");
String[] colors = scanner.nextLine().split(" ");
int n = colors.length;
boolean[] used = new boolean[n];
for (int i = 0; i < n; i++) {
used[i] = true;
dfs(colors[i], nums[i], 1, n, colors, nums, used);
used[i] = false;
}
System.out.println(ans);
}
public static void dfs(String curColor, String curNum, int pathLen, int n, String[] colors, String[] nums, boolean[] used) {
ans = Math.max(pathLen, ans);
for (int i = 0; i < n; i++) {
if (used[i]) {
continue;
}
if (curColor.equals(colors[i]) || curNum.equals(nums[i])) {
used[i] = true;
dfs(colors[i], nums[i], pathLen + 1, n, colors, nums, used);
used[i] = false;
}
}
}
}
#include
#include
using namespace std;
int ans = 0;
void dfs(string curColor, string curNum, int pathLen, int n, vector<string>& colors, vector<string>& nums, vector<bool>& used) {
ans = max(pathLen, ans);
for (int i = 0; i < n; i++) {
if (used[i]) {
continue;
}
if (curColor == colors[i] || curNum == nums[i]) {
used[i] = true;
dfs(colors[i], nums[i], pathLen + 1, n, colors, nums, used);
used[i] = false;
}
}
}
int main() {
string input;
getline(cin, input);
string input2;
getline(cin, input2);
vector<string> nums;
vector<string> colors;
size_t pos = 0;
while ((pos = input.find(' ')) != string::npos) {
nums.push_back(input.substr(0, pos));
input.erase(0, pos + 1);
}
nums.push_back(input);
pos = 0;
while ((pos = input2.find(' ')) != string::npos) {
colors.push_back(input2.substr(0, pos));
input2.erase(0, pos + 1);
}
colors.push_back(input2);
int n = colors.size();
vector<bool> used(n, false);
for (int i = 0; i < n; i++) {
used[i] = true;
dfs(colors[i], nums[i], 1, n, colors, nums, used);
used[i] = false;
}
cout << ans << endl;
return 0;
}
时间复杂度:O(N!)
。递归树的深度最大为N
,长度最大为N!
,总的时间复杂度为O(N * N!) = O(N!)
空间复杂度:O(N)
。递归树的深度为编译栈所占空间。
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多