464. Can I Win(something needed to be solved!)

写博客之前还是贴一下广州的天气:


生活在广州的同学们傻傻分不清楚是冬天还是夏天。。。。。。

下面我们进入正题:

题目:

In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.

What if we change the game so that players cannot re-use integers?

For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.

Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.

You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.

解析:

1.首先我们来看看原始的"game 100的情况",这种情况下,数字可以重复利用,其中的optimally原则意思是---两则取数的原则都是一样的。如果数字可以重

复利用,那我们就不需要记录那些数字是被使用过 的。那么我们可知道从1-11之间的数的情况,正如题目中分析的。现在我们假设maxChoosableInter=10,

desiredTotal=24,那么我们就会有如下初始表格:


我们知道所有从1-10之间的数字可以重复使用,那么我们的动态规划状态转移方程有:

result(n)=~result(n-d),其中d在[1,maxchoosableInter]之间。因为我们要求当desiredTotal=n时第一个拿数的player能不能获胜的结果无外乎第一

个player首先在[1,maxchoosableInter]之间随机拿一个数,当第一个player拿完之后,问题就变成第二player在[1,maxchoosableInter]之间先拿一个数(但此时

desiredTotal=n-d)能不能获胜的情况了,如果他不能,则第一个player获胜。只要在result(n-d)之间的任意一个为假,那么先拿的player就可以获

胜。。。。既然可重复利用数字的情况解决了,那我们来解决不可重复利用数字的情况。。。


显然,当数字不可重复利用时,我们需要额外的变量来保存那些数字是被使用过的,可以采用至上而下的DFS+动态规划解决。。对于DFS中的每一个状态

我们要知道的信息无非就两个:

1. 当前状态下,那些数字是被使用过的;

2. 目前的desiredTotal还剩下多少;

对于第一点,我参考的是discuss里的大神的(方法很妙!),第二点就是每次调用的时候减去当前还没有被选择的数。

AC代码:

class Solution {
public:
	bool canIWin(int maxChoosableInteger, int desiredTotal) {
		int sum = (1 + maxChoosableInteger)*maxChoosableInteger / 2, current_state=0;
		if (sum < desiredTotal)return false; 
		if (desiredTotal <= 0)return true;
		vector<int>used(maxChoosableInteger,0);
		return search(desiredTotal,used,current_state);
	}

	bool search(int tar,vector<int>&used,int current_state){
		int size = used.size();
		if (tar <= 0)return false;
		map<int, bool>::iterator iter = has.find(current_state);
		if (iter == has.end()){//如果没有
			for (int i = 0; i < size; i++){//逐步查找used中的每一个数
				if (used[i] == 0){//说明没被使用
					used[i] = 1;
					int now = pow(2,i);
					if (!search(tar - (i + 1), used,current_state+now)){//如果不成功
						has.insert(make_pair(current_state, true));
						used[i] = 0;
						return true;
					}
					used[i] = 0;
				}
			}
			has.insert(make_pair(current_state, false));
		}
		iter = has.find(current_state);
		return (*iter).second;
	}
private:
	map<int,bool>has;//代表在int值状态下先拿会赢的集合
};
但是,在做的过程中,以下两条语句(A)和(B)的执行结果很不一样,其中(A)正确,但是(B)错误:

第一种:

bool search(int tar, vector<int>&used){
	int value = booltoint(used), size = used.size();
	if (tar <= 0)return false;
	map<int, bool>::iterator iter = has.find(value);
	if (iter == has.end()){//如果没有
		for (int i = 0; i < size; i++){//逐步查找used中的每一个数
			if (used[i] == 0){//说明没被使用
				used[i] = 1;
				if (!search(tar - (i + 1), used)){//如果不成功
					has.insert(make_pair(value, true));
					used[i] = 0;
					return true;
				}
				used[i] = 0;
			}
		}                                                                    
		has.insert(make_pair(value, false));
	}
	return false;//(A)
}
第二种:

bool search(int tar, vector<int>&used){
	int value = booltoint(used), size = used.size();
	if (tar <= 0)return false;
	map<int, bool>::iterator iter = has.find(value);
	if (iter == has.end()){//如果没有
		for (int i = 0; i < size; i++){//逐步查找used中的每一个数
			if (used[i] == 0){//说明没被使用
				used[i] = 1;
				if (!search(tar - (i + 1), used)){//如果不成功
					has.insert(make_pair(value, true));
					used[i] = 0;
					return true;
				}
				used[i] = 0;
			}
		}
		has.insert(make_pair(value, false));
	}
	iter = has.find(value);//(B)
	return (*iter).second;
}
当时以为如果for循环没有找到的话,那么在当时value值的状态为假!。那么如果为假的话,我们在if循环之后就可以直接返回false值,其实是一样的,为什么

算例(10,40)的时候出现问题?????至今还没明白,求高人指点!!!!!!




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值