codeforces 4d dp

题意:有一堆信封和一个礼物,要用信封把礼物包起来,信封可以互相包裹,前提是长宽严格大于被包裹的信封,求最多可以包多少个信封,并且输出它们。

思路:

1、先筛选,把能够包的下礼物的信封留下。

2、按宽排序,如此,合法序列一定是这个序列的子序列

3、dp。 result[i] = result[1...i - 1] + 1。result[i]:前i个信封可包裹的最大信封数。

4、因为还要输出各个信封,所以在第三步时要记录各个状态的前驱

#include <bits/stdc++.h>
using namespace std;
struct node{
	int width;
	int height;
	int number;
	bool operator < (const node &a)const{
		return width < a. width;
	}
};
int main(){
	int n, w, h;
	int tempw, temph;
	int maxval = 1, best = 0;
	cin >> n >> w >> h;
	vector <node> vec;
	for(int i = 0; i < n; i ++){
		cin >> tempw >> temph;
		if(tempw > w && temph > h)
			vec. push_back({tempw, temph, i + 1});
	}
	sort(vec. begin(), vec. end()); 
	n = vec. size();
	if(n == 0){
		cout << 0 << endl;
		return 0;
	}
	vector <int> result(n, 1);
	vector <int> pre(n, -1);
	for(int i = 1; i < n;i ++){
		for(int j = 0; j < i; j ++){
			if(vec[j]. width < vec[i]. width && vec[j]. height < vec[i]. height && result[j] + 1 > result[i]){
				result[i] = result[j] + 1;
				pre[i] = j;   //记录第 i 个元素的前一个元素 
			}
		}
		if(result[i] > maxval){  //选出最大的子序列 
			maxval = result[i];
			best = i;
		}
	}
	cout << maxval << endl;
	result. clear();
	while(best != -1){
		result. push_back(best);
		best = pre[best];
	}
	n = result. size();
	for(int i = n - 1; i >= 0;i --)
		cout << vec[result[i]]. number << " ";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/86503990