动态规划-猜石头
你和你的朋友面前有一排石头堆,用一个数组 piles 表示,piles[i] 表示第 i 堆石子有多少个。你们轮流拿石头,一次拿一堆,但是只能拿走最左边或者最右边的石头堆。所有石头被拿完后,谁拥有的石头多,谁获胜。
石头的堆数可以是任意正整数,石头的总数也可以是任意正整数,这样就能打破先手必胜的局面了。比如有三堆石头 piles = [1,100,3]
,先手不管拿 1 还是 3,能够决定胜负的 100 都会被后手拿走,后手会获胜。
假设两人都很聪明,请你设计一个算法,返回先手和后手的最后得分(石头总数)之差。比如上面那个例子,先手能获得 4 分,后手会获得 100 分,你的算法应该返回 -96。
public static void main(String[] args) { testA(); } static class NodeA { private int first; private int second; public NodeA(int first, int second) { this.first = first; this.second = second; } public String toString() { return "(" + first + " ," + second + ")"; } } /** * a为整数数组,A与B两人分别从a最前或者最后拿元素,A先手与后手分别拿的合集合计 */ public static void testA() { int[] a = {3, 9, 1, 2, 1}; //定义dp二维数组 NodeA[][] dp = new NodeA[a.length][a.length]; //初始化值 for (int i = 0; i < a.length; i++) { for (int j = 0; j < a.length; j++) { if (i == j) { dp[i][j] = new NodeA(a[i], 0); } else { dp[i][j] = new NodeA(0, 0); } } } for (int i = 0; i < a.length; i++) { for (int j = 0; j < a.length; j++) { System.out.print(dp[i][j].toString()); } System.out.println(); } //动态转移公式 //dp[i][j]=max( a[i] + dp[i+1][j], a[j] + dp[i][j-1]) for (int i = 0; i < a.length; i++) { for (int j = i; j < a.length; j++) { if (i != j) { int first = 0; int second = 0; first = Math.max(a[i] + dp[i + 1][j].second, a[j] + dp[i][j - 1].second); if (a[i] + dp[i + 1][j].second >= a[j] + dp[i][j - 1].second) { dp[i][j] = new NodeA(first, dp[i + 1][j].first); } else { dp[i][j] = new NodeA(first, dp[i][j - 1].first); } } } } for (int i = 0; i < a.length; i++) { for (int j = 0; j < a.length; j++) { System.out.print(dp[i][j].toString()); } System.out.println(); } }
算法参考:https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247484496&idx=1&sn=d04bb89cb1df241993c6b46ffcabae7e&source=41#wechat_redirect
收藏文章数量从多到少与“把书读薄”是一个道理