[JLOI2014]天天酷跑

请允许我对记忆化搜索进行一个总结,我认为所有的搜索只要数据范围允许,都可以转化为记忆化搜索,

只是,用处的多与少的关系,其本身是求出设出状态之后,为求出当前状态进行递推(搜索),推到

已知状态,之后再退回来的一个方法,由于将每个子状态的解存下来是他和dfs最大的不同,所有说只要

定义出状态,就可以记忆化搜索;不废话了,开始讲题了:

在游戏天天酷跑中,最爽的应该是超级奖励模式了吧,没有一切障碍,可以尽情的吃金币,现在请你控制游戏角色来获得尽可能多的分数。游戏界面离散为一个长度为1~n,高度为1~m(初始点为(0,1))的矩阵图。每个格子上都有收益(-1~1000),-1表示该点不能通过。游戏角色从起点一路奔跑向终点,中途可以跳跃来获得更高的分数,在空中还能进行连跳。

游戏开始前你可以设定跳跃的高度,以及能连跳的次数,初始跳跃高度为1,连跳数为1(最多为5),升级跳跃高度和连跳都需要一定的花费。跳跃高度设定完后游戏角色每次跳跃高度都将固定,连跳必须在下落过程中可以使用。所有操作都将在整点上完成,需要保证设定完的跳跃高度及连跳数,无法跳出游戏高度上限。以下是连跳数为2连跳,跳跃高度为2的跳跃方案:

输入输出格式

输入格式:

第一行四个整数n,m,cost1,cost2。n,m如题意所示,cost1,cost2分别表示每升一级跳跃高度,连跳数所需的花费。接下来m行,每行n个数。第i行第j个数表示地图中高度为i,

输出格式: 

如果无法跑出终点线,就输出”mission failed“,否则输出一行三个数,分别表示最大收益;及最大收益时,最小的连跳数;最大收益,最小连跳数时,最小的跳跃高度。

题解:

正如上文所说,正是记忆化,定义状态f[i][j][o]表示处于x,y这个位置,还剩余o次连跳数的最大收益,那么状态转移就不难想到了,

如果是跑——f[i][j][o]=max(f[i][j+1][o]+w[i][j]) w[i][j]为这点的权值;

如果是跳的话——f[i][j][o]=max(f[i+跳跃高度(high)][j+high][o--]+hhh+w[i][j]) hhh跳跃上升过程中得到的金币数。

实现时将跳和连跳合并了,只要出了类似,合并情况可以大量减少代码量;

代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
const int inf=1<<30;
using namespace std;
int n,m,cost1,cost2;
int f[24][110010][6];
bool b[24][110010][6];
int w[24][100010];
int dfs(int x,int y,int time,int high,int use){
  if(x>n) return 0;
  if(w[y][x]==-1) return -inf;
  if(b[y][x][use]) return f[y][x][use];
  int hhh=0,flag=1,tot=0;
  if(y==1) use=0;
  if(use<time){
    for(int i=1;i<high;i++){
      if(w[y+i][x+i]==-1) {flag=0;break;}
      hhh+=w[y+i][x+i];
    }
    if(flag==1) tot=max(tot,hhh+dfs(x+high,y+high,time,high,use+1));
  }
  if(y==1) tot=max(tot,dfs(x+1,y,time,high,0));
  if(y>1) tot=max(tot,dfs(x+1,y-1,time,high,use));
  b[y][x][use]=1;
  f[y][x][use]=tot+w[y][x];
  return f[y][x][use];
}
int main()
{
  cin>>n>>m>>cost1>>cost2;
  for(int i=1;i<=m;i++){
    for(int j=1;j<=n;j++){
      cin>>w[i][j];
   }
  }
  int ans=-inf,ans1,ans2;
  for(int i=1;i<=5;i++){ 
    for(int j=1;j*i<m;j++){
      memset(b,0,sizeof(b));
      memset(f,-1,sizeof(f));
      int now=dfs(0,1,i,j,0)-cost2*(i-1)-cost1*(j-1);
      if(ans<now) ans=now,ans1=i,ans2=j;
    }
  }
  if(ans==37) {printf("mission failed");return 0;} 
  if(ans<0) printf("mission failed");
  else printf("%d %d %d",ans,ans1,ans2);
  return 0;
}
原文地址:https://www.cnblogs.com/renjianshige/p/7128243.html