[NOIP模拟][记忆化搜索][动态规划]游戏
来源:互联网 发布:淘宝斗鱼刷人气违规吗 编辑:程序博客网 时间:2024/06/05 09:07
题目描述:
题目大意:有n个物品排成一排,从左往右第i个价值为a[i],有两个人从左往右轮流取物品。第一个人可以拿一或两个物品。如果前一个人拿了k个,下一个人只能拿k或k+1个。如果剩下的物品不够拿,就结束。问如果大家都采取最优策略,那么先手拿的物品的价值最多能比后手多多少。(1≤n≤20000)
样例输入:
1
3
1 3 2
样例输出:
4
题目分析:
考场总结:考试时,觉得这道题特别像前面做得一道题分玩具,于是按照以前那个思路写dp,结果没写对,然后用同样的思路写了个暴力dfs,30分。结果考完评讲的时候,发现我的代码只须将每次dfs返回的值记录下来,记忆化一下就满分了!!!论30分与100分的差距~~~其实考试的时候主要是没有想到状态有重复。
分析:
搜索:其实每个人每次的选择面临的决策是一样的,都是想使自己拿的最大。当上一个人拿到了i且是通过拿到k个拿到的,当前拿的人就只有拿k个或拿k+1个两种选择。当前多的价值就是当前人拿的k个的价值和减去剩下部分能拿出的最大情况(另一个人会想拿的最大,即dfs的返回值)。于是以此dfs,然后记录下来,记忆化搜索一下。
DP:设dp[i][k]表示从第i个物品开始先手拿k个后最多能比后手多取的价值,则:
dp[i][k]=sum[i~i+k-1]+max(dp[i+k][k],dp[i+k+1][k+1])
注意到k最多取到200(20000<1+2+……+200),所以第二维只用开到200即可。
PS: 其实DP和dfs运用的思想是一样的。DP方法懒得写,于是DP的分析和代码都来自于cdsszjj的博客的博文NOIP模拟 Game 【博弈论】【动态规划】
附代码:
1、搜索:
#include<iostream>#include<cstring>#include<string>#include<cstdlib>#include<cstdio>#include<ctime>#include<cmath>#include<cctype>#include<iomanip>#include<algorithm>using namespace std;const int N=20100;int t,n,a[N],sum[N],dp[N][210];int readint(){ char ch;int i=0,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') {ch=getchar();f=-1;} for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0'; return i*f;}inline int dfs(int po,int k,int w)//po代表前一个人拿到了po,且是通过k拿的,w是那一段区间和{ if(po>n) return 0; if(dp[po][k]!=-1) return dp[po][k];//说明已经搜索过 int ret,ret1,ret2; ret1=dfs(po+k,k,sum[po+k]-sum[po]); ret2=dfs(po+k+1,k+1,sum[po+k+1]-sum[po]); ret=max(ret1,ret2); return dp[po][k]=w-ret;}int main(){ //freopen("game.in","r",stdin); //freopen("game.out","w",stdout); t=readint(); while(t--) { memset(dp,-1,sizeof(dp)); n=readint(); for(int i=1;i<=n;i++) a[i]=readint(); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; printf("%d\n",max(dfs(1,1,sum[1]),dfs(2,2,sum[2]))); } return 0; }
2、DP:
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#define ll long longusing namespace std;int getint(){ int i=0,f=1;char c; for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-')f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f;}const int N=20005,K=205;int T,n;ll a[N],dp[N][K];int main(){ //freopen("game.in","r",stdin); //freopen("game.out","w",stdout); T=getint(); while(T--) { memset(dp,0,sizeof(dp)); memset(a,0,sizeof(a)); n=getint(); for(int i=1;i<=n;i++) a[i]=a[i-1]+getint(); for(int i=n;i;i--) for(int k=1;i+k-1<=n&&k<=i+1&&k<=200;k++) dp[i][k]=a[i+k-1]-a[i-1]-max(dp[i+k][k],dp[i+k][k+1]); /*for(int i=1;i<=n;i++) for(int k=1;k<=n;k++) printf("dp[%d][%d]: %d\n",i,k,dp[i][k]);*/ cout<<max(dp[1][1],dp[1][2])<<'\n'; } return 0;}
- [NOIP模拟][记忆化搜索][动态规划]游戏
- 动态规划-记忆化搜索
- poj 1088 记忆化搜索||动态规划
- 动态规划和记忆化搜索
- 记忆化搜索算法之动态规划
- poj 1088+动态规划+记忆化搜索
- EOJ 1823 【动态规划】 【记忆化搜索】
- 动态规划_记忆化搜索
- 动态规划_记忆化搜索
- POJ088滑雪(记忆化搜索|动态规划)
- 动态规划(记忆化搜索)
- hdu1501 zipper【记忆化搜索】【动态规划】
- 动态规划 乘电梯 记忆化搜索
- NOIP模拟题 2016.10.13 [贪心] [记忆化搜索]
- sum游戏 Game of sum uva 10891 动态规划 备忘录(记忆化搜索)
- [NOIP模拟][动态规划]permut
- [NOIP模拟][动态规划]hello
- NOIP模拟 table 动态规划
- Ajax问题总结
- TCP/IP数据包封装与拆解概述
- 取石子游戏(威佐夫博弈)
- 非负矩阵分解NMF
- JAVA集合类汇总
- [NOIP模拟][记忆化搜索][动态规划]游戏
- c++11多线程编程(一):创建线程的三种方法
- spring cloud Ribbon 2 (客户端负载均衡)
- 如何实现UML图的逻辑(C++)
- 51Nod-1428-活动安排问题
- read/write函数实现文件的copy
- Codeforces Round #426 (Div. 2) C The Meaningless Game
- C++ 设计模式-》中介者模式(Mediator)
- NOI模拟(10.29)T2 棋盘