1. 程式人生 > >洛谷3257 [JLOI2014]天天酷跑(DP)(記憶化搜尋)

洛谷3257 [JLOI2014]天天酷跑(DP)(記憶化搜尋)

題目

每次往上跳或往下掉或持平……(具體看題目吧),使路徑上的權值和最大。

題解

記憶化搜尋
設f[i][j][t]表示從出發點到(x,y)這個位置(不含這個位置,即減掉ma[x][y])還可以跳t次的最大權值和。
轉移方程

f[i][j][t]=\max \left\{ f[i+1][j-1][t]+ma[i+1][j-1] , f[i+h][j+h][t-1]+w \right\},其中w表示這一路上的點權和。
下面說說前輩繞的彎路,
注意一下輸入,第一行是底~
再注意一點,回到底後可以重置可跳次數~
考慮細緻一點,這題還是不難的~

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=(1<<30)-1;
const int maxn=100010,maxm=25;

int n,m,cost1,cost2;
int ma[maxn][maxm];

int h,c;
int f[maxn][maxm][6];
int dfs(int x,int y,int t)//在(x,y)還能跳t次
{
    if(y<1||y>m || t<0) return -inf;
    if(~f[x][y][t]) return f[x][y][t];
    if(ma[x][y]==-1) return f[x][y][t]=-inf;
    if(x>=n) return f[x][y][t]=0;
    int re;
    /*if(y>1) re=dfs(x+1,y-1,t)+ma[x+1][y-1];//debug*/
    if(y>2) re=dfs(x+1,y-1,t)+ma[x+1][y-1];//debug
    else if(y==2) re=dfs(x+1,y-1,c)+ma[x+1][y-1];
    else re=dfs(x+1,y,c)+ma[x+1][y];//re=max(re, dfs(x+1,y,t) );
    int sum=0;
    for(int i=1;i<=h;i++) sum+=ma[x+i][y+i];
    re=max(re, dfs(x+h,y+h,t-1)+sum);
    f[x][y][t]=re;
//    printf("(%d %d %d %d)\n",x,y,t,f[x][y][t]);
    return re;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&cost1,&cost2);
    for(int i=1;i<=m;i++)//debug輸入不要倒序 //i要倒序輸入
        for(int j=1;j<=n;j++) scanf("%d",&ma[j][i]);//debug ma[j][i]
    int ans=-1,ansc,ansh;
    for(c=1;c<=5;c++)//最大連跳c次 
    {
        for(h=1;h*c<m;h++)//跳躍高度為h 
        {
            memset(f,-1,sizeof(f));
//            puts("--------------------------------------------");
            int tmp=dfs(0,1,c)-cost1*(h-1)-cost2*(c-1);
            if(tmp>ans)
            {
                ans=tmp;
                ansc=c;ansh=h;
            }
        }
    }
    if(~ans) printf("%d %d %d\n",ans,ansc,ansh);
    else puts("mission failed");
    return 0;
}