区间dp||记忆化搜索 Game of Sum UVA
来源:互联网 发布:淘宝龙瞎皮肤多少钱 编辑:程序博客网 时间:2024/05/17 03:43
最近的个人赛dp
题目链接
This is a two player game. Initially there are n integer numbers in an array and players A and B get
chance to take them alternatively. Each player can take one or more numbers from the left or right end
of the array but cannot take from both ends at a time. He can take as many consecutive numbers as
he wants during his time. The game ends when all numbers are taken from the array by the players.
The point of each player is calculated by the summation of the numbers, which he has taken. Each
player tries to achieve more points from other. If both players play optimally and player A starts the
game then how much more point can player A get than player B?
Input
The input consists of a number of cases. Each case starts with a line specifying the integer n (0 <
n ≤ 100), the number of elements in the array. After that, n numbers are given for the game. Input is
terminated by a line where n = 0.
Output
For each test case, print a number, which represents the maximum difference that the first player
obtained after playing this game optimally.
Sample Input
4
4 -10 -20 7
4
1 2 3 4
0
Sample Output
7
10
题目大意:有n个石头排成一条排,然后有两个人来玩游戏, 每个人每次可以从两端(左或右)中的任意一端取走若干个石头(获得价值为取走石头之和), 但是他取走的方式一定要让他在游戏结束时价值尽量的高,两个人都很聪明,所以每一轮两人都将按照对自己最有利的方法去取数字,请你算一下在游戏结束时,先取数的人价值与后取数人价值之差。
解题思路:dp函数返回的是i到j玩家1可以取得最大值。
#include<stdio.h> #include<stdlib.h> #include<algorithm> #include<string.h> using namespace std; int S[105], A[105], d[105][105], vis[105][105], n; int dp(int i, int j) { //dp函数返回的是i到j玩家1可以取得最大值 if (vis[i][j]) return d[i][j]; vis[i][j] = 1; int m = 0; for (int k = i + 1; k <= j; k++) { m = min(m, dp(k, j)); } for (int k = i; k < j; k++) { m = min(m, dp(i, k)); } d[i][j] = S[j] - S[i - 1] - m; return d[i][j]; } int main() { while (scanf("%d", &n), n) { memset(vis, 0, sizeof(vis)); S[0] = 0; for (int i = 1; i <= n; i++) { scanf("%d", &A[i]); S[i] = S[i - 1] + A[i]; } printf("%d\n", 2 * dp(1, n) - S[n]); //dp(1, n) - (S[n] - dp(1, n)) } return 0; }
参考博客
java版:
总和是一定的,所以一个人的得分越高,另一个人的得分越低。所以我们可以分析,另一个人在所能取得所有最优选择中得分最低的分数 m ,sum-m即为我的最高得分。用d(i,j) 表示原 序列 [i...j] 在双方都采取最优的策略的情况下,先手得分的最大值。对方肯定有一种可能是得0分,因为先手(先手是相对的,并不就是指第一个取的人)可以取完所有的。d(i,j) = sum(i,j) – min{ d(i+1,j), d(i+2,j), … , d(j,j) , d(i,j-1), d(i,j-2), … , d(i,i) , 0 }下面是Java记忆化搜索的代码:import java.io.BufferedInputStream;import java.util.Arrays;import java.util.Scanner;public class Uva_19461 { static int n, sum[] = new int[101]; static int dp[][] = new int[101][101]; static boolean vis[][] = new boolean[101][101]; //记忆化搜索 static int dp(int a,int b){ if(vis[a][b]) return dp[a][b]; vis[a][b] = true; int m = 0; for(int k=a+1; k<=b; k++) m = Math.min(m, dp(k,b) ); //枚举右半部分 for(int k=a; k<b; k++) m = Math.min(m, dp(a,k) );//枚举左半部分 dp[a][b] = sum[b] - sum[a-1] - m ; return dp[a][b]; } public static void main(String[] args) { Scanner s = new Scanner(new BufferedInputStream(System.in)); while(true){ n = s.nextInt(); if(n == 0) break; sum[0] = 0; Arrays.fill(vis[0],false); for(int i=1; i<=n; i++){ sum[i] = sum[i-1] + s.nextInt(); Arrays.fill(vis[i],false); } System.out.println(2*dp(1,n) - sum[n]); } }}
3:dp版
题意:有n个数排成一行,现在A和B两人从两端取任意个数(每次至少取一个),直到取完所有的数,A先取,求A取得数的和比B大多少?思路:区间DP,dp[i][j] 表示区间i~j A取得数的和比B大多少,那么可以这样分析:对于区间i~j 对于先手A可以先取sum[k]-sum[i-1]或sum[j]-sum[k](只能从两端取),然后该B取了,即对于区间k+1~j和i~k 这样即为DP转换为B比A大多少了,所以状态转移方程为 dp[i][j]=max(dp[i][j],max(sum[k]-sum[i-1]-dp[k+1][j],sum[j]-sum[k]-dp[i][k]));
#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;int sum[105];int dp[105][105]; ///A比B大多少?int main(){ int T,Case=1; int n; while(cin>>n) { if(n==0)break; sum[0]=0; for(int i=1; i<=n; i++) { scanf("%d",&sum[i]); sum[i]+=sum[i-1]; } memset(dp,0,sizeof(dp)); for(int i=1; i<=n; i++) dp[i][i]=sum[i]-sum[i-1]; for(int len=1; len<n; len++) { for(int i=1; i<=n; i++) { if(i+len>n) break; dp[i][i+len]=sum[i+len]-sum[i-1]; for(int k=i; k<i+len; k++) { dp[i][i+len]=max(dp[i][i+len],max(sum[k]-sum[i-1]-dp[k+1][i+len],sum[i+len]-sum[k]-dp[i][k])); } } } printf("%d\n",dp[1][n]); }}
4:参考一下leaderboard上的优化写法
- Uva 10891 Game of Sum - 区间DP..记忆化搜索
- 区间dp||记忆化搜索 Game of Sum UVA
- UVA 10891 Game of Sum dp(记忆化搜索)
- UVA 10891 Game of Sum 记忆化搜索
- UVa 10891 Game of Sum / 记忆化搜索
- UVA 10891 Game of Sum(记忆化搜索+博弈)
- 28.uva 10891 Game of Sum 记忆化dp
- Uva 10891 - Game of Sum ( 区间dp )
- uva 10891 Game of Sum 区间dp
- UVA 10891 Game of Sum 区间dp
- UVA 10891 Game of Sum (区间DP)
- UVA 10891 Game of Sum(区间DP),
- UVa UVA 10891 Game of Sum (区间DP)
- sum游戏 Game of sum uva 10891 动态规划 备忘录(记忆化搜索)
- uva 10891 - Game of Sum(博弈,区间dp)
- UVA 10891 - Game of Sum(区间dp)
- uva 10891 Game of Sum(区间dp)
- UVa 10891 Game of Sum (区间DP&博弈)
- 关于HTTP调用接口的四种方式(post,get,delete,put)
- 【设计模式】单例模式(Singleton Pattern)
- leetcode Letter Combinations of a Phone Number
- ios oc与js的交互总结
- 2017年第18届立嘉国际机械展览会会刊(参展商名录)
- 区间dp||记忆化搜索 Game of Sum UVA
- 扫描分析代码漏洞的强大工具
- vue.js使用axios实现跨域请求
- 复合主键与联合主键
- 10. Regular Expression Matching
- 超实平面上函数的微分定义
- kafka配置文件详细
- Ubuntu 搭建Ghost1.0博客系统
- 金蝶K3录单时物料的仓库和默认仓库不一致给予提示,取消该提示框