首页 > 其他分享 >P1156 垃圾陷阱

P1156 垃圾陷阱

时间:2023-11-05 16:24:17浏览次数:34  
标签:状态 const int max 垃圾 陷阱 P1156 trash dp

P1156 垃圾陷阱

基本思路

[受这题的影响](P2370 yyy2015c01 的 U 盘 - 加固文明幻景 - 博客园 (cnblogs.com)),我总觉得这题不应该直接把时间当作状态方程的值,于是搞了\(F[i][j]\),为前\(i\)个物品,前\(j\)时间内能到达的最大高度,然后又搞一个数组维护最优时间,但我的能力根本行不通。

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct Trash {
	int t, h, f;
	bool operator < (const Trash& rhs) const {
		return t < rhs.t;
	}
};

const int N = 101;

int D, G;
Trash a[N];
int F[N][1010], T[N];

int main()
{
	cin >> D >> G;T[0] = 10;
	for (int i = 1; i <= G; i++)
	{
		cin >> a[i].t >> a[i].f >> a[i].h;
	}
	for (int i = 1; i <= G; i++)
	{
		T[i] = T[i - 1];
		int timeI = (a[i].t - a[i - 1].t), timeSum = T[i];
		if (T[i] - timeI <= 0)
		{
			T[i] = 10 + a[i].f;
			continue;
		}
		for (int j = 1; j <= a[G].t; j++)
		{
			F[i][j] = F[i - 1][j];
			if (j >= timeI)
			{
				if (F[i][j] < F[i - 1][j - timeI] + a[i].h)
				{
					F[i][j] = F[i - 1][j - timeI] + a[i].h;
					T[i] = timeSum - timeI;	
				} 
				else
				{
					T[i] = timeSum + a[i].f; 
				}	
			}
			if (F[i][j] >= D)
			{
				cout << T[i];
				return 0;	
			}	
		}
	} 
	cout << T[G];
	return 0;
}

显然,这个算法只能保证在无生命限制下的最优解,无法兼顾生命限制来求最优解。事实上我的\(T[i]\)如果想正常维护的话可能还得开一个动态规划,但是我觉得太复杂了,没办法只能看题解。

题解思路

首先分析题目

每个垃圾都可以用来吃或堆放”,浓浓的透露出一个背包气息。我们可以类比背包问题的放或不放。于是\(DP[i][i]\)描述为处理前\(i\)个物品的某状态\(j\),那么状态\(j\)代表什么呢?

继续分析并使用排除法

我们需要求的答案是时间,于是很自然而然的想到\(j\)描述高度或生命,而\(dp\)数组存放时间。很显然,这样状态既不完整,也写不出转移方程。而且\(dp\)数组存的是当前状态下最大或最小的价值,似乎也不满足。

这时候我们发现,有4个值可能成为状态,高度,生命,物品和时间,难道要dp三维的吗?

再分析题目,每个垃圾都有一个下落的时间,奶牛一定是在垃圾丢下来的时间就处理垃圾的(可以得出这样的最优的),那么物品就可以和时间关联起来了。这时候,我们可以把时间仅仅当作干扰量给剔除了。

需要注意的是,物品的使用顺序并不是随意的,必须按它们下落的时间顺序来先后处理。(这里排一下序即可)

那么\(j\)代表什么呢?

一下子我们并不能得出答案。先尝试\(dp[i][j]\)代表前\(i\)件物品处理后在\(j\)血量时达到的最大高度。

值得一提的是,\(j\)血量表示奶牛在暂时不考虑时间时所得到的最大血量

据说这个是叫离线

状态转移方程

\(dp[i][j] = max(dp[i- 1][j] + trash[i].h, dp[i - 1][j + trash[i].c])\)

发现这是对的,然而我们再想想,在关于\(j\)的一重循环里面,对\(j\)的取值我们似乎并不好判断,甚至要枚举很大。

所以我们再尝试讨论\(dp[i][j]\)代表前\(i\)件物品处理后在\(j\)高度时达到的最大血量

状态转移方程

\(dp[i][j] = max(dp[i- 1][j] + trash[i].c, dp[i - 1][j - trash[i].h])\)

发现这样也是对的,而且\(j\)枚举起来也比较方便,于是我们选择这种算法。


实现该转移方程DP

先讨论所谓的离线算法(我也不知道是不是这样叫的)

意思就是先处理完所有的状态奶牛可以达到的血量再与时间进行讨论

这里我们使用填表法(填表法就是利用状态转移方程和上一个状态来推导出现在的状态

dp[0][0] = 10,因为一开始有\(10\)血

    for(int i=1;i<=g;i++)
        for(int j=0;j<=d;j++)
        {
            if(dp[i-1][j]>=trash[i].t)
                dp[i][j]=max(dp[i][j],dp[i-1][j]+trash[i].c);
            if(j>=trash[i].h&&dp[i-1][j-trash[i].h]>=trash[i].t)
                dp[i][j]=max(dp[i][j],dp[i-1][j-trash[i].h]);
        }

需要非常非常注意的是状态的能否使用

对于以前的状态\(dp[i'][j']\)能否使用,我们的要求是\(dp[i'][j'] >= trash[i].t\)既它还没死

最后扫一遍

    int maxh=0;
    int maxt=0;
    int i;
    for(i=1;i<=g;i++)
    {
        for(int j=0;j<=d;j++)
        {
            if(dp[i][j]-trash[i].t>=0)
                maxh=max(maxh,j);
            maxt=max(maxt,dp[i][j]);
        }
        if(maxh==d)
            break;
    }
    if(maxh==d)
        cout<<trash[i].t<<endl;
    else
        cout<<maxt<<endl;

这里的maxt实际只用讨论\(max(dp[i][0])\)就行了


在线的和刷表法

刷表法就是利用当前的状态,把有关联的下一状态都推出来

在线的思路是,\(dp[i][j]\)所描述的血量是当前时间(既第\(i\)件物品落下时)所真正具有的血量,而不是忽略时间。

int maxt=0;
    for(int i=0;i<g;i++)
    {
        for(int j=0;j<=d;j++)
        {
            if(dp[i][j]>=trash[i+1].t-trash[i].t)
            {
                dp[i+1][j+trash[i+1].h]=max(dp[i+1][j+trash[i+1].h],dp[i][j]-(trash[i+1].t-trash[i].t));
                dp[i+1][j]=max(dp[i+1][j],dp[i][j]+trash[i+1].c-(trash[i+1].t-trash[i].t));
            }
            if(dp[i+1][j+trash[i+1].h]>=0&&j+trash[i+1].h>=d)
            {
                cout<<trash[i+1].t<<endl;
                return 0;
            }
        }
        if(dp[i][0]!=-1)
            maxt=max(maxt,dp[i][0]+trash[i].t);
    }

在这里我们边做边判断是否上去了并更新它的最长存活时间

代码实现

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct Trash {
	int t, h, f;
	bool operator < (const Trash& rhs) const {
		return t < rhs.t;
	}
};

const int N = 101;

int D, G;
Trash a[N];
int maxH, maxT;
int F[N][1010];

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 + G + 1);
	F[0][0] = 10;
	for (int i = 1; i <= G; i++)
	{
		for (int j = 0; j <= D; j++)
		{
			if (F[i - 1][j] >= a[i].t)
			{
				F[i][j] = max(F[i][j], F[i - 1][j] + a[i].f);	
			}
			if (j >= a[i].h && F[i - 1][j - a[i].h] >= a[i].t)
			{
				F[i][j] = max(F[i][j], F[i - 1][j - a[i].h]);
			}
		}
	} 
	for (int i = 1; i <= G; i++)
	{
		for (int j = 0; j <= D; j++)
		{
			if (F[i][j] >= a[i].t)
			{
				maxH = max(maxH, j);
 			}
 			maxT = max(maxT, F[i][j]);
		}
		if (maxH == D)
		{
			cout << a[i].t;
			return 0;
		}
	}
	cout << maxT;
	return 0;
}

标签:状态,const,int,max,垃圾,陷阱,P1156,trash,dp
From: https://www.cnblogs.com/kdlyh/p/17810629.html

相关文章

  • python的内存泄漏及垃圾回收机制
    python内存泄漏的几种场景: 一,如果打开一个文件,不关闭,是不是就是内存泄漏了? 在Python中,打开的文件对象会一直存在内存中,直到显式地关闭文件或者程序结束时才会被清理。因此,如果打开了一个文件但没有关闭它,那么这个文件对象会一直占用内存,导致内存泄漏。为了避免内存泄漏问题......
  • 汽车托运有什么陷阱
    汽车托运行业迅速发展,越来越多的汽车托运公司兴起,在给车主朋友带来便利的同时,许多车主朋友也在汽车托运上吃了亏。下面这4个托运陷阱,10个人有9个中招,一起往下看看吧~陷阱一:坑蒙车主,多次收费部分托运公司靠着客户不懂行情,看人看车定价。提醒大家托运前一定要看清合同上......
  • 基于亚博k210+arduino 智能垃圾桶(23工训赛)
    #20231015派大星改#objectclassifierboot.py#generatedbymaixhub.comfromfpioa_managerimport*frommodulesimportultrasonicfromfpioa_managerimportfmfromMaiximportGPIOimportmathimportstructimportsensor,image,lcd,timeimportKPUas......
  • P1156 垃圾陷阱
    P1156垃圾陷阱考虑设计状态转移方程\(dp_{ij}=\;?\)本题一共有四个参数:物品、高度、生命值、时间,然后考虑如何定义\(i\)、\(j\)和\(dp_{ij}\)。于是可以按照垃圾的出现时间来排序,而物品作为第一维\(i\)表示考虑前\(i\)个垃圾。然后就剩下了[高度、生命值]两个值了,因......
  • java陷阱之关于数据同步
    需求需要查询设备列表。使用redissearch,需要从cannal->kafka->redis问题保证数据有序性和一致性(运维那边不能根据设备id进行分区,到时消息消费时面临消费的有序性问题)采用的是不使用binlog日志修改信息,采用通过id在数据库实时查一次。但是因为有些字段高频修改导致同步的时......
  • Angular 中 Lazy Loading 的陷阱与最佳实践
    在Angular应用程序的开发过程中,性能优化一直是一个关键问题。其中之一是使用懒加载(LazyLoading)来延迟加载应用程序的某些部分,以减小初始加载时间并提高用户体验。然而,在实施LazyLoading时,开发人员可能会陷入一些常见的错误,本文将详细介绍这些错误以及如何避免它们。为什么要使......
  • Java 垃圾回收机制
    目录垃圾回收的基础知识堆空间的基本结构内存分配和回收原则对象优先在Eden区分配大对象直接进入老年代长期存活的对象将进入老年代GC分类对象是否可被回收引用计数算法可达性分析算法引用类型强引用(StrongReference)软引用(SoftReference)弱引用(WeakReference)虚引用(PhantomRefere......
  • 基于Java的垃圾分类管理系统
    (文章目录)具体实现截图主要功能:基于java(ssm)垃圾分类管理系统系统分为小区和管理员两个角色小区的主要功能有:1.小区管理者登陆系统2.垃圾分类信息查看3.垃圾站信息查看4.垃圾运输信息查看5.小区管理者在线报修申请,删除,修改,查询报修信息6.小区管理员在线投诉,删除,修改,查......
  • splay + 垃圾回收 知识点与例题的简要讲解
    splay简要讲解前置芝士:普通二叉树splaytree是一个越处理越灵活的数据结构,通过splay(伸展)操作,使整棵树的单次查询时间复杂度接近于O(logn),整棵树的高度也接近于logn根据上面的这句话,很明显能看出splay与普通二叉树的区别普通二叉树经过多次处理后,很容易退化成链,单......
  • 智慧垃圾站:AI视频智能识别技术助力智慧环保项目,以“智”替人强监管
    一、背景分析建设“技术先进、架构合理、开放智能、安全可靠”的智慧环保平台,整合环境相关的数据,对接已建业务系统,将环境相关数据进行统一管理,结合GIS技术进行监测、监控信息的展现和挖掘分析,实现业务数据的快速收集、全面整合、深度挖掘、智能分析、按需共享,发挥数据资源价值,构建......