Fire

这篇博客介绍了如何解决一道关于最大价值营救物品的问题,涉及到动态规划和优先级队列的知识。Polycarp需要在火灾中尽可能抢救价值最高的物品,每个物品有其救援时间和燃烧时间。通过排序和动态规划算法,可以找到最大价值总和及救援顺序。代码中展示了如何实现这一算法,包括输入处理、排序、动态规划状态转移和回溯打印救援顺序。

引子
一道简单背包,只是记忆方面卡了很久

题目描述

Polycarp惹了很大麻烦——他的房子着火了!由于火势太大,短时间内无法灭火。设大火燃烧的时间为0时刻,Polycarp想从大火中带走价值总和尽量多的物品。每次他只能带走一个,且营救两件物品的时间间隔为0。分别给出挽救第i件物品需要的时间为ti,开始燃烧的时间di(在d时间开始燃烧就不能再挽救该物品了),该物品的价值pi。在di时刻,第i件物品将被彻底烧毁,对他来说将不再有任何价值;如果ti≥di,那么第i件物品不能得救。

假设他从第0时刻开始营救物品,求他能从大火中能够带走物品的最大价值总和,并输出物品总数以及救援物品的顺序(物品的编号为输入的顺序)

输入格式

第一行: 物品总数n(1<=n<=100) 以下n行,每行分别三个整数ti(1<=ti<=20),di(1<=di<=2000),pi(1<=pi<=20)

输出格式
第一行: 能带走的最大的价值总和

第二行: 这些物品的数量 一行,数与数用空格分隔开,分别是能带走物品的编号(按读入顺序)

样例

样例输入 1

3
3 7 4
2 6 5
3 7 6

样例输出 1

11
2
2 3

样例输入 2

2
5 6 1
3 3 5

样例输出 2

1
1
1

代码时间

#include<bits/stdc++.h>
using namespace std;
int n,dp[2005],f[2005][2005],ANS,t;
struct Fire{
	int t,d,p,num;
}a[105];
stack<int>fire;
void print(int i,int j){
	if(i<=0||j<=0)return;
	if(j>=a[i].d)print(i,j-1);
	else if(f[i][j]==1){
		fire.push(a[i].num);
		print(i-1,j-a[i].t);
	}
	else print(i-1,j);
}
bool cmp(Fire x,Fire y){return x.d<y.d;}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].t>>a[i].d>>a[i].p;
		a[i].num=i;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		for(int j=a[i].d-1;j>=a[i].t;j--){
			if(dp[j-a[i].t]+a[i].p>dp[j]){
				dp[j]=dp[j-a[i].t]+a[i].p;
				f[i][j]=1;
			}
		}
	}
	for(int i=0;i<=2000;i++)ANS=max(ANS,dp[i]);
	for(int i=0;i<=2000;i++){
		if(ANS==dp[i]){
			t=i;
			break;
		}
	}
	cout<<ANS<<endl;
	print(n,t);
	cout<<fire.size()<<endl;
	while(!fire.empty()){
		cout<<fire.top()<<" ";
		fire.pop();
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值