Java使用动态规划解决博弈问题

动态规划解决博弈问题

石头游戏:
你和你的朋友⾯前有⼀排⽯头堆,⽤⼀个数组 piles 表⽰,piles[i] 表⽰第 i 堆⽯⼦有多少个。你们轮流拿⽯头,⼀次拿⼀堆,但是只能拿⾛最左边或者 最右边的⽯头堆。所有⽯头被拿完后,谁拥有的⽯头多,谁获胜。 ⽯头的堆数可以是任意正整数,⽯头的总数也可以是任意正整数,这样就能 打破先⼿必胜的局⾯了。⽐如有三堆⽯头 piles = [1,100, 3] ,先⼿不管 拿 1 还是 3,能够决定胜负的 100 都会被后⼿拿⾛,后⼿会获胜。 假设两⼈都很聪明,请你设计⼀个算法,返回先⼿和后⼿的最后得分(⽯头 总数)之差。⽐如上⾯那个例⼦,先⼿能获得 4 分,后⼿会获得 100 分,你 的算法应该返回 -96。

分析

首先 这个问题和常规的问题不同,先手和后手会相互影响,所以在dp table 中存在两个状态 fir, sec;

1 明确dp[i][j] = (fir, sec)的含义

对于第i到第j堆的石头,先手最多拿到fir个,后手最多拿到sec的个
2.初始化base情况
1)因为i<j 所以
if i>j dp[i][j] == 0
2)如果i==j 必然只有一个石头堆,先手获得 后手为0 即 dp[i][j] = {pile(i),0};

2 确定状态转移方程

当前dp[i][j] 和那些因素有关呢?

1.对于先手来说

1)他可以选最左边 即pile[i], 选择了之后 对于 dp[i-1][j] (i+1~j 石头堆)来说就是后手了,所以 dp[i][j]fir = dp[i+1][j].sec + pile[i];
2)他也可以选左边 即pile[j] ,选择了之后 对于dp[i]j-1来说就是后手了,所以 dp[i][j] sec = dp[i][j-1].sec + pile[j];
先手要选择最大的即 max(dp[i+1][j].sec + pile[i], dp[i][j-1].sec + pile[j]);

2.对于后手来说

后手的选择 取决于先手的选择
1)若先手选择了左边 则剩下i+1 ~j 的石头堆来说,后手变成了先手 即dp[i][j].sec = dp[i+1][j].fiir;
2)若先手选择了右边 则剩下i ~j-1的石头堆来说,后手变成了先手 即dp[i][j].sec = dp[i][j-1].fiir;

总结

不管先手还是后手 dp[i][j]的值只和dp[i+1][j] 和dp[i][j-1]的值有关 类似于图
在这里插入图片描述
此时的dp table 采用斜向遍历的方式 具体代码

int game(int[] pile){
	int n = piles.length;
	//三维数组 最后一个维度代表两个状态 先手和后手
	int[][][] dp = new int[n][n][2]
	//base 根据上文分析
	for(int i = 0; i < n;i++){
	//先手拿到
	dp[i][i][0] = piles[i];
	//后手没有
	dp[i][i][1] = 0;
	}
	//斜向便利数组
for	(int l=2;l<=n;l++)	{										
	 for(int i =0;i<=n-l;i++)	{
 		int j = l + i- 1;												
	//	先⼿选择最左边或最右边的分数												
		int	left = piles[i] + dp[i+1][j][1];												
		int	right = piles[j] + dp[i][j-1][1];												
	//	套⽤状态转移⽅程	
		if	(left > right)	{																
		dp[i][j][0] = left;																
		dp[i][j][1] = dp[i+1][j][0];												
		}else{			
		dp[i][j][0]=right;
		dp[i][j][1]	=dp[i][j-1][0];
		}								
	}				
}	
	return dp[0][n][1] - dp[0][n][0];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值