[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; }