双元素LIS问题
Mysterious Present
(codeforces 4D)
题目镜像
题面翻译
给出一个限制\((w,h)\)和 \(n\) 个物品的二维信息\((w_i,h_i)\)
求物品二维都满足 \(w_i>w,h_i>h\) 的前提下的最长二维严格上升子序列以及其长度\((w_i>w_{i-1},h_i > h_{i-1}\) )
如果找不到任何一个物品满足条件 只需输出一行 0
解题报告
不难看出这道题就是一个最长上升子序列(LIS)问题的加强版
把原本的一维问题扩展到了二维,我们参考LIS的思想还是可以用DP完美解决这个加强版问题
首先,我们先来复习一下LIS的代码
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i]=1;
}
for(int i=2;i<=n;i++)
for(int j=1;j<i;j++)
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,dp[i]);
但我们仔细想一想就会发现,实际上这道题目前还不是严格的二维LIS
因为序列中的元素是可以互换顺序的
所以选出的一个序列是不符合子序列的定义的
既然我们要保证\(w_i>w_j\) 和 \(h_i>h_j\)同时成立
但只有每一次迭代都是\(i>j\)时,我们才方便用DP进行
那我们不妨把\(w_i>w_j\)关联到\(i>j\)上,
那么,
$ dp_i $ = \(max\) {\(dp_i, dp_j+1\) | \(i>j\) -> \(w_i>w_j ,h_i>h_j\)}
把\(w_i>w_j\)关联到\(i>j\)的过程我们可以用一个结构体的sort实现
这样以后,这个问题实际上就退化为一维LIS了
$ dp_i $ = \(max\) {\(dp_i, dp_j+1\) | \(w_i!=w_j ,h_i>h_j\)}
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=5050;
int n,w,h;
struct node{
int w,h,id;
}a[N];
int tot,dp[N],pre[N],b[N];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int main()
{
cin>>n>>w>>h;
for(int i=1;i<=n;i++)
{
int wi,hi;
cin>>wi>>hi;
if(wi>w && hi>h)
{
node t;
t.w=wi;t.h=hi;t.id=i;
a[++tot]=t;
}
}
sort(a+1,a+1+tot,cmp);
for(int i=1;i<=tot;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
if(a[i].h>a[j].h && a[i].w!=a[j].w && dp[i]<dp[j]+1)
{
dp[i]=dp[j]+1;
pre[i]=j;
}
}
int ans=0,pos;
for(int i=1;i<=tot;i++)
if(dp[i]>ans)
{
ans=dp[i];
pos=i;
}
int t=ans;
while(pos!=0)
{
b[t]=a[pos].id;
pos=pre[pos];
t--;
}
cout<<ans<<endl;
for(int i=1;i<=ans;i++)
cout<<b[i]<<" ";
return 0;
}