博弈搜索中的记忆化

先看下面几道题目 

uva 11884   http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23316

hdu 4778  http://acm.hdu.edu.cn/showproblem.php?pid=4778

hdu 4753  http://acm.hdu.edu.cn/showproblem.php?pid=4753

这几道题目都是这个类型的,但是刚开始并没有弄得十分清楚,现在拿出来整理一下。

题意:

(1)有一些方块摆在地上,alice和bob可以轮流对方块进行射击,现在射击会有随机性,随机发生三种情况,询问双方采用最优策略,询问先手胜利概率是多少?

(2)每个包中有一些颜色块,包数不超过21个,alice和bob轮流选择一个包丢入一个共享的锅中,如果现在锅中某一种颜色的的数目超过S,那么就可以获得一块魔法石通过消去S个一样的颜色块,并且可以获得一次额外的机会,现在询问双方采用最优的策略, max( Va - Vb) 是多少。

(3)现在在一个4*4的方格图中,每两个点之间可以存在有一条边,现在如果加入一条边形成一个四边形,得一分,两个四边形,得两分,双方采用最优策略,现在max(Va-Vb)


思路:

在这类问题中,一个很明显的特征,双方要求采用最优策略,这个就是一个很显然的极大极小过程搜索,将每一步转化成一个状态,然后配合上极大极小搜索的剪枝利器,alphabeta剪枝,代码框架如下

int alphabeta(State &s,int player ,int alpha,int beta) {
	if(s.isfinal())
		return s.score;

	vector<State> children;
	s.expand(player, children);
	
	int n = children.size();
	for(int i = 0;i < n;i++ ) {
		int v = alphabeta(children[i] , 1 - player, alpha,beta);
		if(0 == player)
			alpha = max(alpha ,v);
		else
			beta = min(beta, v);
		if(beta <= alpha)
			break;
	}
	return !player ? alpha : beta;
}


这就是一个极大极小搜索加上alphabeta剪枝之后的代码。

在以上几道题目中,这个算法无情的tle了。

仔细看这个算法,几乎将所有状态遍历了一遍,但是拿第二道题为例来看,如果将每一个包看成一个资源,那么消耗掉相同的资源之后,不论前面的得分是怎么样的,现在锅中的状态是确定的,那么接下去先手的人一定会采用对他来说最有利的策略,所以这里不就是搜了很多次了嘛?

所以这个地方可以用记忆化的方法记录下来,框架还是采用alphabeta搜索的框架,对接下去的状态采用最优选择策略并记录下来。

那么他和alphabeta这个算法看着确实很像,但是还有一些细节差距。

先放代码

int dfs(State s) {
    if(INF != dp[s.s])
        return dp[s.s];
    if(all == s.s)
        return dp[s.s] = 0;

	vector<State> children;
	vector<int > score;

	s.expand(children, score);

	int n = children.size();
	int ret = -INF;

	for(int i = 0;i < n; i++) {
		int ans = dfs(children[i]) + score[i];
		ret = max(ret ,ans);
	}
    return dp[s.s] = ret;
}

是不是和alphabeta代码很像啊,确实。

因为这个算法就是在之间的搜索上改的,按照我们普通的思想进行了记忆化,这里要注意的是,现在dfs往下走的时候 我们就不用当前路径上的得分了,因为这些状态其实是不确定的,我们这里计算的时候之后的路径上的最优解,在取最优值的时候需要加上当前这步的收获减去后继的dp值,为什么?因为我们这里定义的都是当前步的先手拿的最大获利,而到了最终态的时候,因为是后继路径的最大值,所以我们return 0;这样递归上去就可以得出正解。

需要注意的是,这样的优化之后就不能使用alphabeta剪枝,而且只能适用于个数较小的时候,否则状态太大,而且必须是前面的状态不会影响到后面的状态才行,否则就不符合记忆化的初衷了。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值