P1149. 2023.03.30-第一题-塔子哥玩游戏(dp)

题目内容
塔子哥是一名拥有独特天赋的冒险者,他拥有一双敏锐的眼睛,能够寻找到别人无法察觉的宝石和宝藏。为了寻找更多的宝藏和宝石,他踏上了一段新的旅程。
在这段旅程中,他来到了一个神秘的游戏世界。这个游戏世界有n 个关卡和 m 种宝石。每一个关卡都有一个boss或商店。当他打败一个boss时,他可以获得一个新的宝石。但是,由于他只能携带一个宝石,他必须丢掉当前的宝石才能取走新的宝石。此外,当他到达一个商店时,商店会收购一种特定的宝石,并给他一些钱。
塔子哥想知道自己最多可以获得多少钱。因此,他开始了他的游戏之旅,希望能在这个游戏世界中获得尽可能多的财富。

输入描述
输入第一行为两个整数 nm ,(1n,m106
接下来 n 行,每一行第一个输入为一个字符,如果字符为 b,则代表boss,后面输入一个整数,代表宝石种类。
如果字符为 m ,则代表商店,后面输入两个整数,代表该商店收取的宝石种类和价格。

输出描述
输出塔子哥最多可以获得多少钱。

样例
输入
5 3
b 3
b 1
m 3 50
b 2
m 1 100
输出
100

很显然宝石只有被出售之后才会获得实际的收益,所以对各个掉落的宝石,可以进行一个抽象的多线程dp
通俗点来说就是,假设没有只允许携带一个宝石这个条件。但是在商店只能卖出一个指定宝石
那么问题就很显然了,以每一次遇到商店作为一个分割,计算每次只卖出一个宝石的最大收益
虽然这种最优解的形式有点贪心那味道,但是第一个样例就指明了这不是贪心,而是动态规划
定义 dp[i] 为第1~i个关卡被探索后选择宝石能达到的最大值
那么可以定义状态转移方程,如果遇到当前位置为boss关,那么记录此时有那个宝石;
如果遇到商店,则出售唯一允许出售的宝石(等价于选择了这个宝石并带到了商店),或者不出售宝石(等价于之前没有拿这个宝石)。

定义f[i]为第i关时能获得的最多的钱,用哈希表与前缀和优化状态转移
如果遇到当前位置为boss关,那么记录此时有那个宝石,f[i]=f[i-1]
如果遇到商店,则出售唯一允许出售的宝石 使用哈希表找到最近一次获得该宝石的位置j
f[i]=max(f[i-1],f[type]+value)

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
int dp[maxn];
int pre[maxn];
int main(){
	int n,m;
	cin>>n>>m;
	memset(pre,-1,sizeof(pre));
	for(int i=1;i<=n;i++){
		dp[i]=dp[i-1];
		char c;
		int type,price;
		cin>>c;
		if(c=='m'){
			cin>>type>>price;
			// 对应不交易宝石和交易宝石两种可能的情况
			if(pre[type]!=-1) dp[i]=max(dp[i],pre[type]+price);//交易或者不交易 
		}
		else{
			cin>>type;
			// 当前打败了boss,获得宝石的选择权
			// 这样写可以联系第一个样例来看,遇到商店一定出售的做法不一定最优,可以有如下选择
			// (1)选择不出售宝石,也就是当前没有拿可以出售的那种宝石,选择从上一次没有交易此宝石的价值转移
			// (2)选择出售宝石,也就是将这个宝石带上,到商店再看,可能卖,可能不卖
			pre[type]=max(pre[type],dp[i]);
		}
	}
	printf("%d\n",dp[n]);
}
posted @   lipu123  阅读(18)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示