题意:Peter想做一个东西送给朋友作为生日礼物。他有N个信封每个信封都有一定的长(h)和宽(w),而且每个信封都有一个编号(从1到N)。他用这些信封做成一个链,要求这个链中的第i个信封的长和宽要严格大于第i-1个信封的长和宽。而且他要在每个信封里装一个长宽分别为H,W的贺卡,当然链中的每个信封的长宽都要严格大于贺卡的长和宽才能装进去(贺卡不允许折叠)。问这个链的最大长度为多少?并输出这个链上的每个信封的编号。
分析:DP。最长上升子序列问题(LIS)。按w或h为第一关键字排个序,进行DP,DP时用一个数组保存一下状态转移方向,以便输出方案。(不是贪心啊啊啊啊。。。%>_<%)
Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define LL long long
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5005;
struct node{
int w,h,id;
}en[maxn];
LL dp[maxn];
int num[maxn],tmp[maxn];
int n,W,H;
bool cmp(node a,node b){
if(a.w==b.w&&b.h==a.h) return a.id<b.id;
if(a.w==b.w) return a.h<b.h;
return a.w<b.w;
}
int main()
{
scanf("%d %d %d",&n,&W,&H);
for(int i=0;i<n;i++){
scanf("%d %d",&en[i].w,&en[i].h);
en[i].id=i+1;
}
sort(en,en+n,cmp);
memset(dp,0,sizeof(dp));
memset(num,-1,sizeof(num));
bool mark=false;
int ans=0,index=0;
for(int i=0;i<n;i++){
if(en[i].w>W&&en[i].h>H){
mark=true;
dp[i]=1;
if(ans<dp[i]){ans=dp[i];index=i;}
for(int j=0;j<i;j++){
if(en[i].w>en[j].w&&en[i].h>en[j].h){
if(dp[i]<dp[j]+1){
dp[i]=dp[j]+1;
num[i]=j;
if(ans<dp[i]){
ans=dp[i];
index=i;
}
}
}
}
}
}
if(!mark) {printf("0\n");return 0;}
int cnt=0;
tmp[cnt++]=en[index].id;
while(num[index]!=-1){
tmp[cnt++]=en[num[index]].id;
index=num[index];
}
printf("%d\n",ans);
for(int i=cnt-1;i>0;i--) printf("%d ",tmp[i]);
printf("%d\n",tmp[0]);
return 0;
}