Guess Number Higher or Lower II 猜数字大小 II

本文探讨了一个猜数游戏的最优策略,目标是最小化猜错数字时累计的成本。通过递归方式寻找最佳猜测数字,并使用备忘录减少重复计算,确保能够以最低成本获胜。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们正在玩一个猜数游戏,游戏规则如下:

我从 到 n 之间选择一个数字,你来猜我选了哪个数字。

每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了。

然而,当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。直到你猜到我选的数字,你才算赢得了这个游戏。

示例:

n = 10, 我选择了8.

第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。
第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。
第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。

游戏结束。8 就是我选的数字。

你最终要支付 5 + 7 + 9 = 21 块钱。

给定一个 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏。

思路:这道题我们来看规律。

1:假如n=1或者n=0,那么cost=0

2:假如n=1,2,那么我们猜较小的误差1,根据反馈可以得到正确答案,cost=1

3:假如n=1,2,3,那么猜2,根据反馈也可以得到正确答案,cost=2

到目前为止还没看出来规律,因为前3种是我们的边界条件(第三种其实可以分解为更详细的子问题,不算边界条件,但是不明显,所以暂不分解)

4:假如n=1,2,3,4,由于我们不知道哪种好,所以只能逐个猜:

    猜k=1,对于左边而言,cost=0,对于右边[2,3,4],根据上面的分析,cost=3。综合来看cost=k+max(cost(left)+cost(right))=1+max(0,3)=4

     猜k=2,对于左边1,cost=0,对于右边3,4,cost=3,综合cost=2+max(0,3)=5

     猜k=3,对于左边1,2,cost=1,对于右边4,cost=0,综合cost=3+max(1,0)=4

     猜k=4,对于左边1,2,3,cost=2,对于右边无,cost=0,综合cost=4+max(2,0)=2

取k=1,2,3,4中对应最小的cost总和是4。对于n=1,2,3,4,cost最小是4。

所以我们用memo[i][j]表示[i,j]范围内的最小的cost,用递归得到如下参考代码:

class Solution {
public:
int helpCore(int start,int end, vector<vector<int>>& memo) {
	if (start >= end) {
		return 0;
	}
	if (start == (end - 1)) {
		memo[start][end] = start;
		return memo[start][end];
	}
	if (memo[start][end] > 0) {
		return memo[start][end];
	}
	int res = INT_MAX;
	for (int k = start+1; k < end; k++) {
		int t = k + max(helpCore(start, k - 1, memo), helpCore(k + 1, end, memo));
		res = min(res, t);
	}
	memo[start][end] = res;
	return memo[start][end];
}

int getMoneyAmount(int n) {
	vector<vector<int>> memo(n + 1, vector<int>(n + 1, 0));
	return helpCore(1, n, memo);
}
};




LeetCode的第374题“猜数字游戏”(Guess Number Higher or Lower)中,玩家和计算机进行一种简单的猜数字游戏。玩家需要猜测一个由计算机随机生成的1到n之间的整数,如果玩家猜的数字太小,计算机会提示“太低”,如果玩家猜的数字太大,计算机则提示“太高”。玩家有最多次数限制来猜测这个数字。 C++中可以使用回溯法(Backtracking)策略来解决这个问题。基本步骤如下: 1. 定义一个递归函数,接受当前猜测的数字、剩余的最大猜测次数以及已尝试过的数字范围。 2. 在函数开始时,设置一个标志变量,表示当前猜测的是最后一次机会。然后从剩余的数字范围内随机选择一个数字作为猜测。 3. 检查猜测的数字与实际数字的关系,如果是正确的,则返回胜利;如果太小,递归地调用函数并减去1次机会;如果太大,直接返回失败。 4. 在所有猜测机会用完之前,继续尝试新的数字,直到找到正确答案或者机会耗尽。 以下是简化的C++代码示例: ```cpp #include <vector> #include <ctime> int guessNumber(int n, vector<int>& guesses) { srand(time(0)); // 初始化随机种子 int target = rand() % (n + 1); // 生成1到n之间的随机数 int attempts = guesses.size(); // 最大尝试次数等于已给出的猜测次数 bool lastChance = false; for (int i = 0; i <= attempts && !lastChance; ++i) { int guess = guesses[i]; // 使用已知的猜测值 if (guess == target) { return i + 1; // 胜利,返回猜测次数 } else if (guess < target) { cout << "太低了 (" << guess << ")"; lastChance = i == attempts - 1; // 如果这是最后的猜测,标记为最后一次机会 } else { // guess > target cout << "太高了 (" << guess << ")"; lastChance = true; } } return -1; // 如果超过最大次数仍未能猜中,返回-1 } // 示例调用 int main() { vector<int> guesses = {2, 3, 5}; // 给出已有的猜测值 cout << guessNumber(10, guesses); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值