洛谷P3800 Power收集【最长上升子序列做法】

题目描述:

题目背景

据说在红雾异变时,博丽灵梦单身前往红魔馆,用十分强硬的手段将事件解决了。

然而当时灵梦在 Power 达到 MAX 之前,不具有“上线收点”的能力,所以她想要知道她能收集多少 P 点,然而这个问题她答不上来,于是她找到了学 OI 的你。

题目描述

可以把游戏界面理解成一个 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 点。

输出格式

一个数字

样例输入

3 3 4 1

1 1 3

1 2 1

2 2 3

3 3 3

样例输出

9

题目分析:

先按照每个P点的行从小到大排个序 

我们考虑dp[i]表示走到第i个P点时power值最大是多少,能由在他上面的个P点走过来,就可以得出以下状态转移方程:

dp[i]=max(dp[i],dp[j]+val[i]);

那么问题来了,需要符合怎样的要求才能进行转移?

我们设上面的P点坐标为P(x,y),下降了L秒即纵坐标下降了L格,由于最大速度为T格每秒,所以下面的P点一定在P(x-L*T,y+L),P2(x+L*T,y+L)这个直线上。故此,我们可以就此完成dp部分代码

for(int i=1;i<=k;i++){
	dp[i]=p[i].v;
	for(int j=0;j<i;j++)
		if(abs(p[i].y-p[j].y)<=t*(p[i].x-p[j].x))//本题x与y颠倒 
			dp[i]=max(dp[i],dp[j]+p[i].v);
	ans=max(ans,dp[i]);
}

到此这个题基本结束,我们把前面的部分写写,在注意下小细节,这个题就出来了 

坑点:

1.注意本题中x是纵坐标,y是横坐标

2.注意初始化,将dp[i]赋值为val[i]

代码:

下面放上本题的AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4005;
int n,m,t,k;
int dp[N];
struct node{
	int x,y,v;
}p[N];
bool cmp(node A,node B){
	return A.x<B.x;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>k>>t;
	for(int i=1;i<=k;i++){
		cin>>p[i].x>>p[i].y>>p[i].v;
	}
	sort(p+1,p+1+k,cmp);
	int ans=0;
	for(int i=1;i<=k;i++){
		dp[i]=p[i].v;
		for(int j=0;j<i;j++)
			if(abs(p[i].y-p[j].y)<=t*(p[i].x-p[j].x))
				dp[i]=max(dp[i],dp[j]+p[i].v);
		ans=max(ans,dp[i]);
	}
	cout<<ans;
	return 0;
}

感想:

奔着单调队列优化dp来的,后来发现就是个LIS水题,感觉可以评黄。加我认为这种做法才是正解,单调队列优化dp纯是想复杂了。看完这篇题解,希望您能对dp有更深的理解,带给您的帮助。也鼓励大家在我的评论区里提出更好的做法。渴望得到大家的支持!!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值