题目链接:http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3816&konwledgeId=41
考点:最长单调递增子序列
解题思路:这道题有两个限制条件w,h。可能出现的情况:w小h大,w大h小。
解题思路:
1.首先去除不满足条件的信封
注意:两个信封之间w和h中只要有其中一个相等,就不可以套装。
2.对满足条件的信封按w从小到大排序,那么接下来我们就单单考虑h大小就好了。这就将两个约束条件转换成了一个。
3.对于上述问题,我们可以转换成求求最长递增子序列。
4.删去3中求出的结果w相等的元素
5.输出结果
代码如下:
#include<stdio.h>
#include<algorithm>
struct stu{
int id,vw,vh;
}mm[5010];
int arr[5010];
using namespace std;
bool cmp(stu a,stu b){
return a.vw<b.vw;
}
int LISS(int l,int res[5010]){
int i,j;
int pre[5010];
int f[5010];
int k=1;//记录最后一个尾元素的位置
int max=1;
//求最长递增序列
for(i=1;i<=l;i++){
pre[i]=i;
f[i]=1;
for(j=1;j<i;j++){
if(mm[j].vh < mm[i].vh && f[j]+1>f[i]){
f[i]=f[j]+1;
pre[i]=j;
}
}
if(f[i]>max){
max=f[i];
k=i;
}
}
j=max;
while(k!=pre[k]){
res[j--]=mm[k].id;
k=pre[k];
}
res[j]=mm[k].id;
return max;
}
int main(){
int n,w,h,i,x,y,j;
while(scanf("%d%d%d",&n,&w,&h)!=EOF){
int l=0;
int res[5010];
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(x<=w||y<=h) continue;
mm[++l].vw=x;
mm[l].vh=y;
mm[l].id=i;
}
if(l==0){//序列长度为0
printf("0\n");
continue;
}
sort(mm+1,mm+1+l,cmp);
int max=LISS(l,res);
//去除w相等的元素,只要其中一个尺寸一样,就不可以装
int d[5010];
x=0;y=0;
for(i=1;i<=max;i++){
for(j=1;j<=l;j++){
if(mm[j].id==res[i]){//注意res里装的是id而不是结构体的下标
break;
}
}
if(mm[j].vw!=x){
d[++y]=res[i];
x=mm[j].vw;
}
}
printf("%d\n",y);
for(i=1;i<y;i++){
printf("%d ",d[i]);
}
printf("%d\n",d[y]);
}
return 0;
}