【noip 2009】 乌龟棋 记忆化搜索&动规
题目背景
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
题目描述
乌龟棋的棋盘是一行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】 乌龟棋 记忆化搜索&动规的更多相关文章
- NOIP 2017 逛公园 记忆化搜索 最短路 好题
题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...
- P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)
传送门 这对抗搜索是个啥玩意儿…… 首先可以发现每一行的棋子数都不小于下一行,且局面可由每一行的棋子数唯一表示,那么用一个m+1进制数来表示当前局面,用longlong存,开map记忆化搜索 然后时间 ...
- Codevs_1017_乘积最大_(划分型动态规划/记忆化搜索)
描述 http://codevs.cn/problem/1017/ 给出一个n位数,在数字中间添加k个乘号,使得最终的乘积最大. 1017 乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提 ...
- 【P2476】着色方案(记忆化搜索+特殊的DP数组)
这个题代码难度几乎为0,然而思维难度对于蒟蒻来说简直是突破天际啊!首先我思考的是这个油漆的种类只有15种,是不是可以像一道叫做8数码难题的东西暴力15维数组呢..计算发现不可以....空间会直接让你学 ...
- 【bzoj1415】【聪聪和可可】期望dp(记忆化搜索)+最短路
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57148470 Descrition 首先很明显是 ...
- 记忆化搜索:POJ1088-滑雪(经典的记忆化搜索)
skiing 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑 ...
- [ACM_动态规划] 数字三角形(数塔)_递推_记忆化搜索
1.直接用递归函数计算状态转移方程,效率十分低下,可以考虑用递推方法,其实就是“正着推导,逆着计算” #include<iostream> #include<algorithm> ...
- 【BZOJ-3895】取石子 记忆化搜索 + 博弈
3895: 取石子 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 263 Solved: 127[Submit][Status][Discuss] D ...
- hdu3555 Bomb (记忆化搜索 数位DP)
http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others) Memory ...
随机推荐
- 利用 gperftools 对nginx mysql 内存管理 性能优化
利用 gperftools 对nginx 与 mysql 进行 内存管理 性能优化 降低负载. Gperftools 是由谷歌开发.官方对gperftools 的介绍为: These tools ...
- url语法
URL的主要部分 URL通常被写成如下形式: <方案>:<方案描述部分> 一个URL包含了它使用的方案名称(<方案>), 其后紧跟一个冒号,然后是一个字符串 (&l ...
- Jquery使用常见(全)
一.选择器实例 语法 描述 $(this) 当前 HTML 元素 $("p") 所有 <p> 元素 $("p.intro") 所有 class=&q ...
- 《数据结构与算法分析:C语言描述》读书笔记------练习1.1 求第K大的数
求一组N个数中的第k个最大者,设k=N/2. import java.util.Random; public class K_Max { /** * @param args */ //求第K大的数,保 ...
- width这样读取出来是一个字符串,并且带有单位,但是offsetwidth返回的是一个数值。
<!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <title> ...
- linux下安装部署环境:jdk、tomcat、nginx
一.安装jdk 一.查看Linux自带的JDK是否已安装 1.查看已经安装的jdk: # rpm -qa|grep jdk ← 查看jdk的信息或直接执行 或 # rpm ...
- Unity3D ——强大的跨平台3D游戏开发工具(一)
众所周知,Unity3D是一个能够实现轻松创作的多平台的游戏开发工具,是一个全面整合的专业游戏引擎.在现有的版本中,其强大的游戏制作功能已 经达到让人瞠目结舌的地步.尤其是它在3.0版本里面制作的那款 ...
- C语言-结构体
C语言中数组是把相同类型的数据类型的变量集中在一起了,而结构体则是把不同类型的变量聚集在一起. 结构体也是一种数据类型,但是它是一种自定义的数据类型,也就是说和使用其他数据类型不一样,我们得先定义这种 ...
- firefox 28.0
Ubuntu 安装 firefox 28.0指令: apt-cache show firefox | grep Version sudo apt-get install firefox=28.0+bu ...
- Sublime Text3 使用手册
1.标签页切换:ctrl+tab 2.Sublime Text3的配色方案(Preferences——配色方案)我选白色方案是:Eiffel;深色方案我选:Monokai 3.左边资源栏:先ctrl+ ...