题目背景

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

题目描述

乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

输入输出格式

输入格式:

输入文件的每行中两个数之间用一个空格隔开。

第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。

第2行N个非负整数,a1a2……aN,其中ai表示棋盘第i个格子上的分数。

第3行M个整数,b1b2……bM,表示M张爬行卡片上的数字。

输入数据保证到达终点时刚好用光M张爬行卡片。

输出格式:

输出只有1行,1个整数,表示小明最多能得到的分数。

输入输出样例

输入样例#1:                                                                    输出样例#1:

9 5                                                          73
6 10 14 2 8 8 18 5 17
1 3 1 2 1

说明

每个测试点1s

小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。

对于30%的数据有1≤N≤30,1≤M≤12。

对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。

对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。

虽然说,暴力出奇迹,但是,暴力终归不是最优解,那么就要用到一些形形色色奇奇怪怪的带有技巧的搜索,就比如记忆化搜索。

基本搜索方式

就是一个dfs,非常简单,此处略。

记忆化搜索

记忆化搜索,官方解释为:算法上依然是搜索的流程,但是搜索到的一些解用动态规划的那种思想和模式作一些保存。

说白了就是把以前搜过的记住,以后就不用搜了,直接调用数组中保存的答案,下面代码中用dp数组进行记录选 i 张1,j 张2,k 张3,l 张4 能得到的最优解。

 #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
int scr[],crd[],m,n,dp[][][][];
int dfs(int i,int j,int k,int l,int now)
{
if(now==n) return ; //到达边界返回0 if(i) //如果第一张卡片有剩余,下同
{
if(dp[i-][j][k][l]) //如果以前搜过,直接调用,下同
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-][j][k][l]+scr[now+]);
else //如果没搜过,那就dfs搜
dp[i][j][k][l]=max(dp[i][j][k][l],dfs(i-,j,k,l,now+)+scr[now+]);
} if(j)
{
if(dp[i][j-][k][l])
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-][k][l]+scr[now+]);
else
dp[i][j][k][l]=max(dp[i][j][k][l],dfs(i,j-,k,l,now+)+scr[now+]);
} if(k)
{
if(dp[i][j][k-][l])
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k-][l]+scr[now+]);
else
dp[i][j][k][l]=max(dp[i][j][k][l],dfs(i,j,k-,l,now+)+scr[now+]);
} if(l)
{
if(dp[i][j][k][l-])
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k][l-]+scr[now+]);
else
dp[i][j][k][l]=max(dp[i][j][k][l],dfs(i,j,k,l-,now+)+scr[now+]);
}
return dp[i][j][k][l]; //将dp中存的结果带回
}
int main()
{
cin>>n>>m;
for(int i=;i<=n;i++)
cin>>scr[i];
for(int i=;i<=m;i++)
{
int x;
cin>>x;
crd[x]++;
} cout<<dfs(crd[],crd[],crd[],crd[],)+scr[]; //注意要加上第一个格子的得分
return ;
}

用记忆化搜索的代码在洛谷上评测 十个点的总时间为 239ms

动态规划

动态规划 即 dp,官方解释为:动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。

说白了就是分阶段的解决问题,对于相同的题目来说,耗时极短,是比赛中的重要解题方法之一,但是动态转移方程的推出也是令许多选手头疼的一大难题,如果写好了记忆化搜索的话,推出动态转移方程也就很简单了。

 #include <iostream>
#include <cstdio>
using namespace std;
int now,scr[],crd[],maxn,m,n,dp[][][][];
int main()
{
cin>>n>>m;
for(int i=;i<=n;i++)
scanf("%d",&scr[i]);
for(int i=;i<=m;i++)
{
int x;
scanf("%d",&x);
crd[x]++;
}
for(int i=;i<=crd[];i++)
for(int j=;j<=crd[];j++)
for(int k=;k<=crd[];k++)
for(int l=;l<=crd[];l++)
{
if(i) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-][j][k][l]);
if(j) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-][k][l]);
if(k) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k-][l]);
if(l) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k][l-]);
//以上四行是由上阶段开始枚举每一张牌来选出目标阶段的最优解
dp[i][j][k][l]+=scr[i+j*+k*+l*+]; //加上当前格子的得分
}
cout<<dp[crd[]][crd[]][crd[]][crd[]];
return ;
}

用动规写的代码在洛谷上评测 十个点的总时间为203ms。

可见动规和记忆化搜索的运行时间基本相同,所以如果能推出动态转移方程并且非常自信的话,当然是用动规好一些,但是如果没有推出动态转移方程 或者你并不确定的话,还是用记忆化搜索好一些。

【noip 2009】 乌龟棋 记忆化搜索&动规的更多相关文章

  1. NOIP 2017 逛公园 记忆化搜索 最短路 好题

    题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...

  2. P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)

    传送门 这对抗搜索是个啥玩意儿…… 首先可以发现每一行的棋子数都不小于下一行,且局面可由每一行的棋子数唯一表示,那么用一个m+1进制数来表示当前局面,用longlong存,开map记忆化搜索 然后时间 ...

  3. Codevs_1017_乘积最大_(划分型动态规划/记忆化搜索)

    描述 http://codevs.cn/problem/1017/ 给出一个n位数,在数字中间添加k个乘号,使得最终的乘积最大. 1017 乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提 ...

  4. 【P2476】着色方案(记忆化搜索+特殊的DP数组)

    这个题代码难度几乎为0,然而思维难度对于蒟蒻来说简直是突破天际啊!首先我思考的是这个油漆的种类只有15种,是不是可以像一道叫做8数码难题的东西暴力15维数组呢..计算发现不可以....空间会直接让你学 ...

  5. 【bzoj1415】【聪聪和可可】期望dp(记忆化搜索)+最短路

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57148470 Descrition 首先很明显是 ...

  6. 记忆化搜索:POJ1088-滑雪(经典的记忆化搜索)

    skiing 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑 ...

  7. [ACM_动态规划] 数字三角形(数塔)_递推_记忆化搜索

    1.直接用递归函数计算状态转移方程,效率十分低下,可以考虑用递推方法,其实就是“正着推导,逆着计算” #include<iostream> #include<algorithm> ...

  8. 【BZOJ-3895】取石子 记忆化搜索 + 博弈

    3895: 取石子 Time Limit: 1 Sec  Memory Limit: 512 MBSubmit: 263  Solved: 127[Submit][Status][Discuss] D ...

  9. hdu3555 Bomb (记忆化搜索 数位DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory ...

随机推荐

  1. Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)

         在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定位不到元素的情况(报selenium.common.exceptions.NoSuchElementException ...

  2. Ubuntu的Redis安装

    转自:http://blog.fens.me/linux-redis-install/ 1. Redis在Windows中安装 在Windows系统上安装Redis数据库是件非常简单的事情,下载可执行 ...

  3. HDU 5652 India and China Origins

    二分答案+验证,注意一开始就不连通的话输出0 #include<cstdio> #include<cstring> #include<cmath> #include ...

  4. iOS友盟三方登陆

    Umeng三方登陆个人总结 Demo地址:https://github.com/haozheMa/UmengThirdLoginDemo这里仅以微信.QQ和新浪微博作为例子首先根据官方文档 导入以下依 ...

  5. STM32F103外部中断编程

    STM32F103外部中断编程   中断,顾名思义就是停下手头的活,去干另外一件急活,干完急活然后回来继续干手头的活. 单片机和人一样,有时候也有更急的程序需要执行,执行完之后再回来执行之前正在执行的 ...

  6. 10天学会phpWeChat——第十天:phpWeChat的会员注册、登录以及微信网页开发

    通过前面的系列教程,我们系统的讲解了phpWeChat从视图端.控制器端到模型端的操作流程:熟悉了phpWeChat的目录结构:掌握了视图端模板如何创建一个丰富的表单和模型端如何操作数据库.这一切都是 ...

  7. 【转】PHP生成随机密码的几种方法

    使用PHP开发应用程序,尤其是网站程序,常常需要生成随机密码,如用户注册生成随机密码,用户重置密码也需要生成一个随机的密码.随机密码也就是一串固定长度的字符串,这里我收集整理了几种生成随机字符串的方法 ...

  8. MySQL密码过期策略

    如果要设置密码永不过期的全局策略,可以这样:(注意这是默认值,配置文件中可以不声明) [mysqld] default_password_lifetime=0 禁用密码过期: ALTER USER ' ...

  9. 如何检测 Android Cursor 泄漏

    简介: 本文介绍如何在 Android 检测 Cursor 泄漏的原理以及使用方法,还指出几种常见的出错示例.有一些泄漏在代码中难以察觉,但程序长时间运行后必然会出现异常.同时该方法同样适合于其他需要 ...

  10. python3自动下载优酷视频小程序

    我们一般都在优酷里看一些好玩的视频,有时候看到精彩的就想下载到本地保存起来留作纪念,在win下可以用维棠等软件下载,但苦了用linux的孩子们.尽管chrome和firefox的一些插件可以下载,但有 ...