当前位置: 首页 > wzjs >正文

网站底部素材wordpress顶部菜单哪里设置

网站底部素材,wordpress顶部菜单哪里设置,久久建筑有限公司,seo推广教程seo高级教程题目 洛谷:P1156 垃圾陷阱 分析 关于本题,状态有三个影响因素:物品,时间(血量),高度。 物品的使用顺序并不是随意的,必须按它们下落的时间顺序来先后处理。所以时间就确定了&…

题目

洛谷:P1156 垃圾陷阱
在这里插入图片描述

分析

关于本题,状态有三个影响因素:物品,时间(血量),高度。
物品的使用顺序并不是随意的,必须按它们下落的时间顺序来先后处理。所以时间就确定了,将物品排序后依次使用即可。现在就只剩下血量,高度。选哪个作为 j 呢?
只能挨着尝试,看哪个更好些,动态规划有的时候选错了状态定义是做不出来题目的,但是本题两种都可以。这里就选择枚举高度作为 j 来解题。

于是有:f[i][j]表示处理完第 i 个垃圾之后,高度为 j 时的最大血量。

重点

这道题与常规的背包问题解法是不同的

举个例子:

  • 常规背包问题(如0/1背包):
    状态定义:f[i][j]表示在前 i 个物品中选,背包容量不超过 j 时的最大价值
    转移方程:
    f[i][j] = f[i-1][j];  // 不选第i个物品
    if (j >= v[i]) {f[i][j] = max(f[i][j], f[i-1][j-v[i]] + w[i]); // 选第i个物品
    }
    
  • 本题垃圾陷阱问题:
    状态定义:f[i][j]表示处理完第 i 个垃圾后,高度为 j 时的最大血量

关键区别:
本题的状态表示是“处理完第 i 个垃圾后”!!!不是简单地考虑"选"或"不选",而是考虑每个垃圾怎么用

每个垃圾有两种使用方式(吃或堆放):

  1. 堆放垃圾会增加高度(j增加)
  2. 吃垃圾会增加血量(f[i][j]的值增加)

我们可以发现:在常规的背包问题中,状态表示都是状态转移方程研究的都是对于(i,j)这个状态的来源,它是由哪些状态转移而来的,研究是什么导致了f[i][j]。例如在经典01背包中,研究(i,j)这个状态,可以分两种情况,选择或者不选。于是我们都是在对当前的f[i][j]做递推。

但是在本题中,根据题意,我们的状态表示是 “处理完第 i 个垃圾后”,这个 “处理完” 就代表着垃圾已经处理了,我们要研究的是垃圾处理后导致了什么。会导致两种可能:要么加血,要么增加高度。于是我们要同时写出这两种状态转移方程。通过堆放垃圾增加高度,或者吃垃圾维持生命,两种操作都会影响不同的状态维度。

代码

dfs

数据范围问题:一般题目限制128MB的时候,开bool类型数组大概能开1e9左右。如果需要开更大的空间就做不到了,这时候可以使用map来储存数据。只不过map的O(logn)相对数组的O(1)就慢一些了。

为什么数据量大时用map?

  • 空间效率:实际问题中,DP状态往往是稀疏的,可能只有少量状态会被实际访问,数组方式会浪费大量空间存储未访问的状态。

  • 灵活性:可以处理状态值范围很大的情况,不受固定数组大小的限制。

  • 避免MLE:当状态空间理论上很大时,例如状态维度是1e5×100×100,数组方式无法存储。

#include<iostream>
#include<algorithm>
#include<map>using namespace std;//bool dp[10010][110][110];
map<int,map<int,map<int,bool>>> dp; //如果题目数据量太大就用mapstruct node
{int t,f,h;
}a[110];int d, g;
int ans1 = 1e9, ans2 = 0;bool cmp(node& a, node& b)
{return a.t < b.t;
}void dfs(int f,int h,int pos)
{if(h >= d) {ans1 = min(ans1, a[pos-1].t);return;}if(f < a[pos].t || pos > g){ans2 = max(ans2, f);return;}if(dp[f][h][pos]) return;dp[f][h][pos] = true;dfs(f + a[pos].f, h, pos + 1);dfs(f, h + a[pos].h, pos + 1);return;
}int main()
{cin >> d >> g;for(int i=1;i<=g;i++){cin >> a[i].t >> a[i].f >> a[i].h;}sort(a + 1,a + 1 + g,cmp);dfs(10,0,1);if(ans1 == 1e9) cout << ans2;else cout << ans1;return 0; 
}

背包dp

在绝对时间中不进行扣血操作。
举个例子,现在是中午12点,你醒了,你是一个机器人,你身上有2个小时电量,到了下午1点天上掉了一个补给包给你充了2个小时电,现在的电量够支撑到下午4点,但是下次掉落补给包在下午5点,于是你噶掉了。这就是比较绝对时间
同样一个故事,还可以这样叙述:现在是中午12点,你醒了,你是一个机器人,你身上有2个小时电量,过去了一个小时,你的电量只剩下1个小时了(绝对时间的下午1点),此时天上掉了一个补给包给你充了2个小时电,现在的电量增加到3个小时了,但是还有4个小时你才能拿到补给包(绝对时间下午5点),于是你噶掉了。

实际上它们是相同的逻辑,都是正确的。我分别写出他们的代码。

比较绝对时间

绝对时间的逻辑:

  • f[i-1][j]表示处理完前i-1个垃圾后,高度为j时的剩余血量

  • 这个血量是从时间0开始累积的"剩余生存时间"

  • 比较f[i-1][j] >= a[i].t 实际上是判断:从开始到现在,剩余的生命是否足够支撑到当前垃圾掉落的时间

完整代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std; const int N = 110, T = 1e5 + 10;int f[N][T]; //f[i][j]表示处理完第i个垃圾之后,高度为j时的最大血量。 处理完第i个垃圾之后!! 
int d,n; //垃圾井深度、垃圾的数量 
struct node
{int t,w,h; //扔下的时间、维持生命的时间、能垫高的高度 
}a[N];bool cmp(node& a, node& b)
{return a.t < b.t;
}int main() 
{cin >> d >> n;for(int i=1;i<=n;i++){cin >> a[i].t >> a[i].w >> a[i].h;	}	sort(a + 1, a + 1 + n, cmp); //排序哪个垃圾最先落下 f[0][0] = 10;for(int i=1;i<=n;i++){	for(int j=0;j<=d;j++){			if(f[i-1][j] >= a[i].t) //能拿到这个垃圾 {if(j + a[i].h >= d) //拿完就出去了,那就直接返回这个物品掉落的时间  {cout << a[i].t << endl;return 0;}//当前物品不能直接垫出去//记住:状态表示是处理完第i个物品!那么处理完会导致两种可能。而不是在1~i个物品中选择,第i个物品的状态是由两种可能性导致的 f[i][j] = max(f[i][j],f[i-1][j] + a[i].w); //吃掉第i个物品导致的状态f[i][j+a[i].h] = max(f[i][j+a[i].h],f[i-1][j]); //堆起来第i个物品导致的状态			 }}}int ret = 10;for(int i=1;i<=n;i++){if(ret < a[i].t) break;else ret += a[i].w;}cout << ret << endl;return 0;
}

问题:为什么不将全部 f 数组初始化为负无穷也是对的?

  • 血量永远不会为负值:因为吃垃圾只会增加血量(+a[i].w),而时间判断f[i-1][j] >= a[i].t已经确保了血量足够
  • 不会选择无效状态:无法到达的状态会保持为0,而有效状态的值都会≥10

比较相对时间

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std; const int N = 110, T = 1e5 + 10;int f[N][T]; //f[i][j]表示处理完第i个垃圾之后,高度为j时的最大血量。 处理完第i个垃圾之后!! 
int d,n; //垃圾井深度、垃圾的数量 
struct node
{int t,w,h; //扔下的时间、维持生命的时间、能垫高的高度 
}a[N];bool cmp(node& a, node& b)
{return a.t < b.t;
}int main() 
{cin >> d >> n;for(int i=1;i<=n;i++){cin >> a[i].t >> a[i].w >> a[i].h;	}	sort(a + 1, a + 1 + n, cmp); //排序哪个垃圾最先落下 memset(f, -0x3f, sizeof f); //负无穷表示无法到达的状态	f[0][0] = 10;for(int i=1;i<=n;i++){int delta = a[i].t - a[i-1].t;for(int j=0;j<=d;j++){if(f[i-1][j] < delta) continue; //撑不到垃圾来就死了//能拿到垃圾 if(j + a[i].h >= d) //拿完就出去了,那就直接返回这个物品掉落的时间  {cout << a[i].t << endl;return 0;}//当前物品不能直接垫出去//记住:状态表示是处理完第i个物品!那么处理完会导致两种可能。而不是在1~i个物品中选择,第i个物品的状态是由两种可能性导致的 f[i][j] = max(f[i][j], f[i-1][j] - delta + a[i].w); //吃掉第i个物品导致的状态f[i][j+a[i].h] = max(f[i][j+a[i].h], f[i-1][j] - delta); //堆起来第i个物品导致的状态			 }}int ret = 10;for(int i=1;i<=n;i++){if(ret < a[i].t) break;else ret += a[i].w;}cout << ret << endl;return 0;
}

重点分析:
将代码写在if(f[i-1][j] >= a[i].t)(绝对时间代码演示中)的条件下,与直接if(f[i-1][j] < delta) continue;(相对时间代码演示中)过滤不符合条件的 j 的枚举是等效的。

Q:f(f[i-1][j] < delta) continue; 撑不到垃圾来就死了为什么还要continue ,直接break不行吗?
A:没有理解动态规划的过程。用 continue 是因为我们要枚举所有可能的高度 j(从 0 到 d),每一个 j 都是一个独立的状态。continue 表示跳过当前状态 j 的处理,继续尝试下一个高度。而 break 会直接退出这个 for 循环,不再检查更高的高度,这会导致状态没有被完整地转移,结果就会出错。

初始化分析:
相对时间中 f 数组必须要初始化为负无穷,因为相对时间下,血量可能会出现负数,会影响判断。

小结:对于动态规划的理解,可以从函数的角度来理解动态规划。我们可以把动态规划看作是在构造一个函数,这个函数的输入是某些“状态参数”,输出是该状态下的“最优值”或“可行性判断”等。如果你知道 f[i-1][j] 是准确的;那你可以只基于这个数值去计算 f[i][j],而不用关心“我是怎么走到 f[i-1][j] 这个状态的”。这跟函数的定义是一致的。函数不记录“历史”,它只关注输入和输出。

*无后效性是指:当前状态一旦确定,后续的决策和状态转移就只与当前状态有关,而与之前如何到达这个状态的路径无关。


文章转载自:

http://0mdr1ndh.trpLf.cn
http://TGzOP5D7.trpLf.cn
http://1JrSBAwf.trpLf.cn
http://KoYPYM94.trpLf.cn
http://vrm2sc7S.trpLf.cn
http://L6ftwn9o.trpLf.cn
http://oiwIa5Vs.trpLf.cn
http://Y1rpQYXH.trpLf.cn
http://bixnt98Q.trpLf.cn
http://FrH2LNKP.trpLf.cn
http://hfnotDSY.trpLf.cn
http://fG0ATpON.trpLf.cn
http://wvJNSx2B.trpLf.cn
http://Qo6GjA62.trpLf.cn
http://Y3qkfLdr.trpLf.cn
http://o6y4j7lv.trpLf.cn
http://2lVOAS9E.trpLf.cn
http://UkhpZ6ya.trpLf.cn
http://aatEI0pV.trpLf.cn
http://FKi7Iuw5.trpLf.cn
http://EUT9mHne.trpLf.cn
http://iRJECMZp.trpLf.cn
http://5IQthX17.trpLf.cn
http://iehQmvi1.trpLf.cn
http://XitEMm4K.trpLf.cn
http://E9oZBiiK.trpLf.cn
http://dqidYoG6.trpLf.cn
http://9zu0uKUz.trpLf.cn
http://DYdd4LHa.trpLf.cn
http://sW3MRSXT.trpLf.cn
http://www.dtcms.com/wzjs/646120.html

相关文章:

  • 宝塔搭建网站教程wordpress综合类网站
  • OA 公司网站 铁道建设报安卓手机做网站服务器吗
  • 香水网站建设规划书福建建筑人才服务中心档案
  • 做平台还是自己做网站网站开发什么技术路线
  • 学生管理系统网站怎么做本地婚姻介绍网站
  • 东山县建设局网站用万网建设网站教程视频
  • 兼职做网站在那里接任务素材设计做的好的网站有哪些
  • 网站推广引流最快方法郑州资讯
  • 仿阿里云网站佛山北京网站建设
  • 上海网站建设方案进入百度官网首页
  • 网站怎么做交易平台大宗商品交易平台网
  • 贵州网站seo工商登记查询系统官网
  • app网站开发后台处理济南手机建站公司
  • 如何做婚介网站网店美工主要学什么
  • 网页游戏平台网站wordpress登录评论
  • 光伏电站建设的国家网站成都调查事务所
  • 关于网站建设的电话销售话术中国工程建设招标网官方网站
  • 网上注册公司流程及步骤上海网站排名优化
  • 商务局网站溪江农贸市场建设建设工程专业承包交易中心网站
  • 深圳金融投资网站建设设计类专业专科学校
  • 网站网页设计要求网站代码优化调整
  • 建立企业网站公司正邦设计的logo
  • 网站开发注意问题室内设计平面图尺寸
  • 杭州专业网站制作做菠菜网站
  • 婚纱摄影团购网站模板西安自由行攻略5天详细
  • 俄文网站建设方案网站开发的实例教程
  • 提供深圳网站制作公司网络编程培训
  • 网站设置了自动登录怎么显示密码电商就业前景
  • 邓州网站建设网站首页logo怎么修改
  • 如何做网站卖衣服下载jsp网站开发用啥工具