四键键盘问题

假设你有一个特殊的键盘,键盘上有如下键:

  • 键1: (A): 在屏幕上打印一个'A'。
  • 键2: (Ctrl-A): 选择整个屏幕。
  • 键3: (Ctrl-C): 复制选择到缓冲区。
  • 键4: (Ctrl-V): 在屏幕上已有的内容后面追加打印缓冲区的内容。

现在,你只能按键盘上N次(使用以上四个键),找出你可以在屏幕上打印的“A”的最大数量

第一种思路:dfs暴力枚举法

我们设置一个dfs递归,他的形参设置为dfs(剩余操作次数,屏幕上a的数字,剪贴板)

dfs(N,a_num,copy)

会发生以下3种操作

如果需要 直接增加A                        dfs(N-1,a_num+1,copy)

由于全选和复制是一起发生的         dfs(N-2,a_num,a_num)

粘贴的操作                                      dfs(N-1,a_num+copy,copy)

 代码如下

#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;
void dfs(int N, int a_num, int copy)
{
	if (N == 0)
	{
		ans =max(ans, a_num);
		return;
	}

	dfs(N - 1, a_num + 1, copy);
	dfs(N - 1, a_num + copy, copy);
	if (N >= 2)
		dfs(N - 2, a_num, a_num);
}
int main()
{
	int N;
	cin >> N;
	dfs(N, 0, 0);
	cout << ans;
}

这样子实际上通过枚举来解决该题的,枚举所有的操作,最后得出屏幕上获得的最多的A字符,由于一共有3种操作,实际上,时间复杂度是很接近于O(3的n次方的),所以我们需要剪枝

记忆化搜索

#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;
int dp[1002][1002][100];
int MAX(int a, int b, int c)
{
	int x;
	a > b ? x = a : x = b;
	x > c ? x : x = c;
	return x;
}
int dfs(int N, int a_num, int copy)
{
	if (N <= 0)
	{
		return a_num;
	}
	if (dp[N][a_num][copy])
		return dp[N][a_num][copy];

	return dp[N][a_num][copy] = MAX(dfs(N - 1, a_num + 1, copy)
		, dfs(N - 1, a_num + copy, copy),
		dfs(N - 2, a_num, a_num));
}
int main()
{
	int N;
	cin >> N;
	cout<<dfs(N, 0, 0);

}

记忆化搜索可以达到一定剪枝的效果,但是诚然,这是完全不够的,我们可以假设一下,在这个算法里,会出现许多 ctrl+c ctrl+a 连续多次的情况,或者没有a就在复制粘贴,这显然是不会得到最多a字符的,我们就需要避免这种情况的发生

第二种思路:dp动态规划 

我们知道,出现最多A字符的情况只会发生在  AAA...复制粘贴(1次或多次)...复制粘贴...AAA...

于是,最后一次的操作,要么是输入A,要么是粘贴,这样子就可以确保在屏幕上出现的A字符是最多的,于是我们需要在一个i的时候,枚举要发生多少次的粘贴,然后用他与输入A作比较,看看这个时候在屏幕上的A数目在选择哪个操作时是最优的

#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;
int dp[1002];
int main()
{
	int N;
	cin >> N;
	for (int i = 1;i <= N;i++)
	{
		dp[i] = dp[i - 1] + 1;			//输入一个A
		//依次枚举发生了i-j次粘贴的情况
		//dp[j-2]表示全选复制时的剪贴板,(i-j+1)中i-j表示粘贴次数,1表示的是dp[j-2]就在屏幕上的A个数
		for (int j = 2;j < i;j++)
		{
			dp[i] = max(dp[i], dp[j - 2] * (i - j + 1));
		}
	}
	cout << dp[N];
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值