CodeForces - 864E FIRE(附带限制条件01背包)

题目链接:CF-864E

题意: Polycarp家中失火了,他有 N 个价值为 pi 的物品,每个物品需要 ti 时间才能
保护下来,但是每个物品在失火开始的 di 时间之前没有保护的话就会坏掉,求他能保护的最大的价值总和.并且输出保存的物品和顺序.

思路: 很明显的一道01背包题,但同时我们还要在取物品的时候记录一下.我们用 dp[i] 表示在失火后的 i 秒时所能保护的最大价值和,j表示第j个物品,则该背包的动态转移方程为:
dp[i] = max(dp[ i-t[j] ]+p[j] ) ( d[j]>i )
从动态方程我们看出,我们需要用比当前 i 的小的时间所存的值去优化,所以为了保证比 i 小的dp值已经是最优的,我们应该先将物品按 d 从小到大排序,再逐步更新dp值.
最后,我们只需从所有时间中选出最大值即可。
AC代码如下:

#include <iostream> 
#include <algorithm>
#include <vector>
using namespace std;

int n;
struct  node{
	int t,d,p,num;
};
node s[110];
vector<int> v[2100];
int dp[2100];
int max_num=0;
bool cmp(node& a,node& b) {
	return a.d<b.d;//从小到大排序,这里要是打‘=’号会re,除非将数组开大。
}

int main() {
	cin>>n;
	for(int i=0;i<n;i++) {
		cin>>s[i].t>>s[i].d>>s[i].p;
		s[i].num=i;
	}
	sort(s,s+n,cmp);
	for(int i=0;i<n;i++) {
		if(s[i].t>=s[i].d) continue;
		for(int j=s[i].d-1;j>=s[i].t;j--) {
			if(dp[j]<dp[j-s[i].t]+s[i].p) {//如果能更新当前值
				dp[j]=dp[j-s[i].t]+s[i].p;
				int k=0;
				v[j].clear();//先清空原先的选取方式
				for(k=0;k<v[j-s[i].t].size();k++) {
					v[j].push_back(v[j-s[i].t][k]);//讲 j-s[i].t的选择方式复制给j
				}
				v[j].push_back(s[i].num);
			}
		}
		//for(int l=0;l<s[n-1].d;l++) cout<<dp[l]<<endl;
		//cout<<' '<<endl;
	}

	for(int i=0;i<s[n-1].d;i++) {
		max_num = dp[i]>dp[max_num] ? i:max_num;
	}
	cout<<dp[max_num]<<endl;
	cout<<v[max_num].size()<<endl;
	for(int i=0;i<v[max_num].size();i++) {
		cout<<v[max_num][i]+1;
		if(i+1<v[max_num].size() ) cout<<' ';
		else cout<<endl;
	}
	return 0;
}

不懂得欢迎在评论区留言.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值