题目链:D. Mysterious Present
题意:
给n个信封,宽和高严格大于另一个信封就可以将他装在里面,信封宽高严格大于卡片就能将卡片装在里面。求最大能套几个信封。
思路:
这题就是和求最长递增子序列一样。先筛掉宽高比卡片小的,然后排序(按长度,宽度都可以)。然后dp,dp[i]的长和宽严格大于dp[j] dp[i]={1–(i-1}中最大的dp[j]+1;遍历完序列找出最大的dp就是答案。这题多了个保存路径。用pre存路径 node存最大的值所对应的节点。pre存上一个节点。比如 最大的dp[i]是在dp[j]的基础上+1,那么pre[i]=j;
代码
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct env
{
env(int x, int y, int z) :w(x), h(y), num(z) {
}
int w, h, num;
bool operator<(const env &a)const
{
return w<a.w;
}
};
vector<struct env>v; //存比卡片大的信封
vector<int>ans; //存路径
//res用来dp 存第i个信封时,最大值。 maxn存最长序列的长度,node存最长序列的最后一个点。
int pre[5100], res[5100], maxn = -1, node = -1;
//将pre初始化为-1;
void init() {
for (int i=0; i < 5010; ++i) {
pre[i] = -1;
}
}
int main()
{
init();
int n, w, h, i, j;
cin >> n >> w >> h;
for (i = 1; i <= n; ++i) {
int W, H;
cin >> W >> H;
if (W>w&&H>h)v.emplace_back(W, H, i);
}
sort(v.begin(), v.end());
if (v.size() == 0)cout << "0";
else {
//dp
for (i = 0; i<v.size(); ++i) {
res[i] = 1;
for (j = 0; j<i; ++j) {
if (v[j].w<v[i].w&&v[j].h<v[i].h&&res[j] + 1>res[i]) {
res[i] = res[j] + 1;
pre[i] = j;
}
}
if (maxn<res[i])
{
maxn = res[i];
node = i; //跟新节点和最大值
}
}
cout << maxn << endl;
//倒推求路径 存在ans里面
while (node!=-1) {
ans.push_back(node);
node = pre[node];
}
//输出路径
for (i = ans.size() - 1; i >= 0; --i)
cout << v[ans[i]].num << " ";
}
return 0;
}