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;
}

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

猜你喜欢

转载自blog.csdn.net/qq_43305984/article/details/88544499