题目背景

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

题目描述

乌龟棋的棋盘是一行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. Quick Cocos2dx 与 DragonBones

    照着官方的例子试验了一下DragonBone的使用,代码如下: local AnotherScene = class("AnotherScene", function() retu ...

  2. HDU 2498 Digits

    水题.题目这样定义的,另f(x)为x有几位,x[i]=f(x[i-1]); 求最小的i使得x[i]==x[i-1] #include<cstdio> #include<cstring ...

  3. 用div做下拉列表

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. Codeforces#364Div2

    A题: 题意:给定一些数,然后每两个组成一对,要求每对的和的大小相同,输出这样的组合 分析:直接模拟就行 #include <iostream> #include <cstdio&g ...

  5. CodeForces 652C Foe Pairs

    只要计算每个位置最多能到哪个位置,累加即可,DP从后往前预处理一下每个位置到达的最远位置. 有坑点:输入的时候如果同一个点出发的,需要保存最小值. #include<cstdio> #in ...

  6. 第三弹:ZFNet

    在所有深度网络中,卷积神经网和图像处理最为密切相关,卷积网在很多图片分类竞赛中都取得了很好的效果,但卷积网调参过程很不直观,很多时候都是碰运气.为此,卷积网发明者Yann LeCun的得意门生Matt ...

  7. MyBatis 3 中使用存储过程

    转:http://zachary-guo.iteye.com/blog/1756689 Mybats 是 iBatis 被 Google 收购后重新命名的一个工程,当然也做了大量的升级.iBatis ...

  8. 苹果应用商店AppStore审核中文指南 分类: ios相关 app相关 2015-07-27 15:33 84人阅读 评论(0) 收藏

    目录 1. 条款与条件 2. 功能 3. 元数据.评级与排名 4. 位置 5. 推送通知 6. 游戏中心 7. 广告 8. 商标与商业外观 9. 媒体内容 10. 用户界面 11. 购买与货币 12. ...

  9. bootstrap tab标签页

    <ul id="myTab" class="nav nav-tabs"> <li class="active"> & ...

  10. 理解Twisted与非阻塞编程

    先来看一段代码: # ~*~ Twisted - A Python tale ~*~ from time import sleep # Hello, I'm a developer and I mai ...