NOIP 2010 乌龟棋

2024-08-25 17:58
文章标签 noip 2010 乌龟

本文主要是介绍NOIP 2010 乌龟棋,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

描述
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行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
6 10 14 2 8 8 18 5 17
1 3 1 2 1
样例输出1[复制]

73

思路

这道题是当年在什么都不懂的情况下参加比赛做的,当时对DP一无所知orz
虽然这题不是特别复杂,不过还是想好好记录一下这题。
乌龟棋的状态比较复杂,每走一步显然都不是一个状态转移,而是由许多卡片一起决定的。
而且这种不像一般的DP可以用矩阵推一推,因为维数显然超过了2维,所以只能进行理论推导。

这道题的突破点在于只有1、2、3、4一共4种步数的卡片,这样使得整个步数及状态的转移控制在一个比较小的范围内。

我一开始所想,以一个4维数组dp[i][j][k][m]表示1、2、3、4的卡片分别**剩下**i,j,k,l张的时候走过的最大值。
注意我标重的“剩下”二字。
这个状态的定义实际上是很有问题的,因为剩下的卡片数和距离没有明确的关系,于是需要再另开一维数组
dp[p][i][j][k][l],表示在位置p的时候,卡片还剩下i,j,k,l的时候,所走过的最大距离
于是列出了如下式子:
dp[p][i][j][k][l]=max{dp[p-1][i-1][j][k][l],
dp[p-2][i][j-1][k][l]
dp[p-3][i][j][k-1][l]
dp[p-4][i][j][k][l-1]}+road[p];
嗯,看起来似乎很顺利…
但是!递推顺序不对啊,还剩i张的状态怎么会在i-1张状态的后面,卡片应当是越来越少的。
于是把i-1改成i+1?
dp[p][i][j][k][l]=max{dp[p-1][i+1][j][k][l],
dp[p-2][i][j+1][k][l]
dp[p-3][i][j][k+1][l]
dp[p-4][i][j][k][l+1]}+road[p];
还是有问题,p是从后往前推的,但是ijkl却是从前往后推的,二者方向相反。
所以会出现一个非常尴尬的情况是不知道从前往后推还是从后往前推好。

然后就没有然后了…

这道题选取状态上有一个很重要的一点是。
选取的卡片对应的步数总量==当前位置
这是个非常重要的点,通过这一点我们就可以将维数从5降低到4
但是如果dp[i][j][k][l]的ijkl还是表示剩下卡片数的话,还是很难以推出之间的关系。
考虑将ijkl表示已经用了多少卡片!!!

这样思路瞬间迎刃而解
我们以dp[i][j][k][l]表示已经用了1234的卡片各ijkl张的时候,所产生的最大价值。
于是仿照我们之前的写法可以很顺畅的写出DP方程

dp[i][j][k][l]=max{dp[i-1][j][k][l],
dp[i][j-1][k][l]
dp[i][j][k-1][l]
dp[i][j][k][l-1]}+road[i+2*j+3*k+4*l];

这样一来求取ijkl状态之前需要求出i-1,j-1等的状态,并且加上当前的位置【i+2*j+3*k+4*l】
于是正推就可以~

#include<stdio.h> 
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<limits>
#include<ctype.h>
#include<algorithm>
#define M 100
#define N 200
#define SN 41
using namespace std;int dp[SN][SN][SN][SN]; int max(int a,int b){return a>b?a:b;
}class Solution{
public:int generate(vector<int> &road,vector<int> &cards){memset(dp,0,sizeof(dp));//abcd表示1234的牌各有多少种 int a=cards[1],b=cards[2],c=cards[3],d=cards[4];for(int i=0;i<=a;i++){for(int j=0;j<=b;j++){for(int k=0;k<=c;k++){for(int l=0;l<=d;l++){int val=0;if(i>0)val=max(val,dp[i-1][j][k][l]);if(j>0)val=max(val,dp[i][j-1][k][l]);if(k>0)val=max(val,dp[i][j][k-1][l]);if(l>0)val=max(val,dp[i][j][k][l-1]);dp[i][j][k][l]=val+road[i+j*2+k*3+l*4];}}}}return dp[a][b][c][d];
//      memset(dp,0,sizeof(dp));
//      //初始时刻获取第一格的分数 
//      dp[0][a][b][c][d]=road[0];
//      int n=road.size(); 
//      //遍历n个点 
//      for(int p=1;p<n;p++){
//          //对于每一点,需要往后推4个位置,并更新那些位置的值
//          for(int i=a;i>=0;i--){
//              if(dp[p-1][i][j][k][l]>0)
//              dp[p][i-1][j][k][l]=max(dp[p-1][i])
//              for(int j=b;j>=0;j--){
//                  for(int k=c;k>=0;k--){
//                      for(int l=d;l>=0;l--){
//                          //可以扩展到4个位置
//                          int target_pos1=p+1*i;
//                          int target_pos2=p+2*j;
//                          int target_pos3=p+3*k;
//                          int target_pos4=p+4*l;
//                          dp[target_pos1][a-i][j][k][l]=dp[p][i][j][k][l]+road[target_pos1];
//                      }
//                  }
//              }
//          } 
//      }}
};/*9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1*/int main(){int n,m;vector<int> road;vector<int> temp,cards;scanf("%d%d",&n,&m);for(int i=0;i<n;i++){int tempv;scanf("%d",&tempv);road.push_back(tempv);}for(int i=0;i<m;i++){int tempv;scanf("%d",&tempv);temp.push_back(tempv);}//cards数组用于计算每一种卡片的数量 cards.resize(temp.size()+5);for(int i=0;i<temp.size();i++)cards[temp[i]]++;Solution solution;int val=solution.generate(road,cards);printf("%d\n",val);
//  system("pause");return 0;}

这篇关于NOIP 2010 乌龟棋的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106254

相关文章

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

【系统架构设计师-2010年】综合知识-答案及详解

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2题】【第3题】【第4~5题】【第6题】【第7~8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20题】【第21题】【第22题】【第23题】【第24题】【第25题】【第26~27题】【第28题】【第29~30题】【第31

如何使用小乌龟清除认证缓存、还原版本、定位及常用开发工具集成

😀前言 本篇博文是关于如何使用小乌龟清除认证缓存、还原版本、定位及常用开发工具集成,希望你能够喜欢 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,感谢大家的观看🥰 如果文章有什么需要改进的地方还请大佬不吝赐教 先在此感谢啦😊 文章目录 如何清除

九度考研真题 浙大 2010-2浙大1006:ZOJ问题

//题目1006:ZOJ问题 #include<iostream> #include<string.h> using namespace std; int main() { char s[1010]; char a[1010];//开始部分 char b[1010]; //中间部分  char c[1010];//后部分  int num1=0,n

九度考研真题 浙大 2010-1浙大1003:A+B

//题目1003:A+B #include<iostream> #include<string.h> using namespace std; int main() { int n1,n2; int s1[12],s2[12]; int s[12]; char c1[20],c2[20]; while(cin>>c1){ n1=0,n2=0;

NOIP 2015 CCF (CSP -J)初赛真题

第二十 一届全国青少年信息学奥林匹克联赛初赛 ; 普及组C++ 语言试题 竞 赛 时 间: 20 1 5 年 1 0 月 1 1 日 1 4 : 3 0~ 1 6 : 3 0 选 手注 意: • 试腰紙共有7 页,答題紙共有2页,满分100 分。请在答感統上炸答,写在試感纸上的一律无 效。 • 不得使用任何电子设 备(如计算器、手机、 电子词典等》或查阅 任何书籍發 料。 一、单项选择题(

在Visual Studio 2010中开发Qt程序

本文演示如何用VS2010开发QT的应用程序界面,前提是已经搭建好了开发环境,搭建方法很简单,我在之前的博客也有描述。此处不再赘述。 1.打开VS2010的IDE开发环境,新建一个QT Application的项目命名为QtGrapher,所有的设置都可以保持默认,创建完成后可以编译运行程序,如果环境配置都正确,会弹出一个空白的GUI界面,如下所示, 2.在IDE的解决方案资源管理器中双

QT+VTK+Visual Studio 2010联合开发

QT+VTK+Visual Studio 2010联合开发 由于开发VTK程序是需要的GUI环境需求比较苛刻,传统的MFC框架在开发简单的GUI程序时还行,稍微复杂一点的程序就显得生硬。因此在开源社区里,开发VTK的GUI程序时,普遍采用QT。以下简单描述这三者的关系。 准备工作,这三者应该提前安装,建议遵循安装顺序为先Visual Studio 2010,再按装QT,再按装CMake,最后安

QT与Visual Studio 2010整合的例子

做GUI界面的设计时,目前已不再拘泥于VS的MFC框架,有很多开源的工具。本例以QT与VS2012的整合为例,演示环境搭建,后续将会用QT做VT的开发工作。 第一步,下载QT和QT与VS的插件,在VS2010下以及结合VTK的情况,网络上经网友实验后效果比较好的版本如下: 1. QT:因为是与VS2010整合,所以选择版本:qt-win-opensource-4.8.5-vs2010.exe,

如何使用 TortoiseGit(小乌龟)进行分支创建、切换与合并以及解决冲突

😀前言 本文将详细介绍如何使用 TortoiseGit(小乌龟)进行分支创建、切换与合并以及解决冲突等操作。TortoiseGit 是一个广泛使用的 Windows 图形化 Git 客户端,其友好的用户界面和丰富的功能使得 Git 操作变得更加直观和便捷。 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里