luogu1156垃圾陷阱题解--背包DP

题目链接

https://www.luogu.org/problemnew/show/P1156

方法1

分析

将已经爬的高度看作背包容积,最大剩余血量看作价值,(f[i][j])表示吃完第(i)个垃圾,爬到(j)高度的最大剩余血量

(f[i][j+h[i]]=max(f[i][j+h[i]],f[i-1][j]-(t[i]-t[i-1])))

(f[i][j]=max(f[i][j],f[i-1][j]+c[i]-(t[i]-t[i-1])))

当然还要判断能否撑到下一个垃圾的到来,以及判断是否已经爬出了陷阱

如果不能爬出,显然将垃圾全部吃完是最优的,因为垃圾全用来吃了并且没撑到下一个时刻,所以(ans=max(ans,f[i][0]+t[i]))

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <iostream>
#define ll long long 
#define ri register int 
using std::min;
using std::max;
template <class T>inline void read(T &x){
	x=0;int ne=0;char c;
	while(!isdigit(c=getchar()))ne=c=='-';
	x=c-48;
	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
	x=ne?-x:x;return ;
}
const int maxn=1005;
const int inf=0x7fffffff;
int f[maxn][105];
bool e[maxn];
int l,m,n;
struct Tra{
	int t,c,h;
	bool operator <(const Tra &b)const{
		return t==b.t?c>b.c:t<b.t;
	}
}tra[maxn];
int main(){
	int dta,h,ans=10;
	read(l),read(n);
	for(ri i=1;i<=n;i++){
		read(tra[i].t),read(tra[i].c),read(tra[i].h);
	}
	std::sort(tra+1,tra+1+n);
	memset(f,-1,sizeof(f));
	f[0][0]=10;
	for(ri i=1;i<=n;i++){
		h=tra[i].h;
		dta=tra[i].t-tra[i-1].t;
		for(ri j=l;j>=0;j--){
			if(f[i-1][j]==-1||f[i-1][j]<dta)continue;
			if(j+h>=l){
				printf("%d
",tra[i].t);
				return 0;
			}
			f[i][j+h]=max(f[i-1][j]-dta,f[i][j+h]);
			f[i][j]=max(f[i-1][j]+tra[i].c-dta,f[i][j]);	
		}
		if(f[i][0]!=-1)ans=max(ans,f[i][0]+tra[i].t);
    /*注意加特判*/
	}
	printf("%d
",ans);
	return 0;
}

方法2

分析

刚刚的方法一点也不背包,我们按着01背包套路把它变成一维的,(f[j])表示爬到了高度(j)总共加上的最大血量.

(f[j+h[i]]=max(f[j+h[i]],f[j]))

(f[j]+=c[i])

按照套路,为了使(j+h[i])这个状态在本阶段中不再出现,我们倒序枚举高度

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#define ll long long 
#define ri register int 
using std::min;
using std::max;
template <class T>inline void read(T &x){
	x=0;int ne=0;char c;
	while(!isdigit(c=getchar()))ne=c=='-';
	x=c-48;
	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
	x=ne?-x:x;return ;
}
const int maxn=1005;
const int inf=0x7ffffff;
int m,n;
struct Tra{
	int t,c,h;
	bool operator <(const Tra &b)const{
		return t<b.t;
 	}
}tr[maxn];
int f[maxn];
int main(){
	read(m),read(n);
	for(ri i=1;i<=n;i++){
		read(tr[i].t),read(tr[i].c),read(tr[i].h);
	}
	std::sort(tr+1,tr+1+n);
	memset(f,-1,sizeof(f));
	f[0]=10;
	for(ri i=1;i<=n;i++){
		for(ri j=m;j>=0;j--){
			if(f[j]>=tr[i].t){
				if(j+tr[i].h>=m){
					printf("%d
",tr[i].t);
					return 0;
				}
				f[j+tr[i].h]=max(f[j+tr[i].h],f[j]);
				f[j]+=tr[i].c;
			}
		}
	}
	printf("%d
",f[0]);
	return 0;
}
原文地址:https://www.cnblogs.com/Rye-Catcher/p/9628325.html