洛谷 P3800 Power收集【DP】

题目描述

可以把游戏界面理解成一个N行M列的棋盘,有K个格子上有P点,其价值为val(i,j)
初始灵梦可以选择在第一行的任意一个格子出发,每秒她必须下移一格。
灵梦具有一个左右移动的速度T,可以使她每秒向左或右移动至多T格,也可以不移动,并且不能折返。移动可视为瞬间完成,不经过路途上的点,只能获得目标格子的P点。
求最终她能获得的POWER值最大是多少?

输入格式:

第一行四个数字,N,M,K,T

接下来K行每行3个数字x,y,v,代表第x行第y列有一个val为v的P点,数据保证一个格子上最多只有1个P点。

输出格式:

一个数字

说明

对于40%的测试点,1<=N,M,T,K<=200
对于100%的测试点,1<=N,M,T,K<=4000
v<=100,N,M,K,T均为整数


题目分析

可能很多人第一眼看过去都以为用dp[i][j]表示走到第i行第j列三层循环就能过.
如果你第一眼不是这么想当我没说.
反正我是这样爆T六个点.

这题的突破口就在于不是每个点都有权值
所以我们只用记录那些有权值的点
然后用那些能到达当前节点的点更新当前结点最大值就好了

具体来说就是先将结点按x坐标升序排序
a b s ( x i x j ) T >= a b s ( y i y j )
就更新 d p [ i ] = m a x ( d p [ i ] = m a x ( d p [ i ] , d p [ j ] + v a l i )


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

int n,m,k,t;
struct node{int x,y,val;}a[5010];
int dp[5010];
int ans=-1e9;
bool cmp(node a,node b){return a.x<b.x;}

int main()
{
    n=read();m=read();k=read();t=read();
    for(int i=1;i<=k;++i)
    a[i].x=read(),a[i].y=read(),a[i].val=read();

    sort(a+1,a+1+k,cmp);
    dp[1]=a[1].val;
    for(int i=1;i<=k;++i)
    {
        for(int j=0;j<i;++j)
        {
            if( abs(a[i].x-a[j].x)*t >= abs(a[i].y-a[j].y) )
            dp[i]=max(dp[i],dp[j]+a[i].val);
        }
        ans=max(ans,dp[i]);
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/80732992