【基础算法】嵌套矩形
时间限制: 1 Sec 内存限制: 128 MB题目描述
有N个矩形,每个矩形可以用两个整数a,b描述,表示它的长和宽。矩形X(a, b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)内。注意,矩形既可以嵌套于它左边的大矩形,也可以嵌套于它右边的大矩形。你的任务是选出尽量多的矩形排成一行,使得除了最后一个外,每一个矩形都可以嵌套在下一个矩形内。
输入
第1行:1个整数N(1<=N<=1000)
第2..N+1行:每行2个整数,分别表示矩形的两个边长。每个矩形依次编号为1~N。
输出
第1行:1个整数K,表示嵌套的最大层数。
第2行:K个整数,表示依次嵌套的矩形的编号。若有多组解,输出字典序最小的一组解。
样例输入
8
14 9
15 19
18 12
9 10
19 17
15 9
2 13
13 10
样例输出
4
4 8 3 2
提示
样例说明:最大嵌套深度为4。4个矩形编号分别是:4 8 3 2,它们的大小关系是:
(9, 10) < (13, 10) < (18,12) < (15,19)
【解】//最长下降(严格)子序列
1,读入时按照每个矩形的较短边为宽,较长边为长处理,并记录其在读入数据中的位置(组数)。
2,按其中一条边从大到小排序,再按照另一条边做一次最长下降子序列并记录路径。(如果做最长上升子序列亲测会错,但原因暂时不明)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int x,y,num;
node(){}
node(int a,int b,int c){x=a;y=b;num=c;}
}r[1010];
int f[1010],pa[1010];
bool cmp(node a,node b){
if(a.x==b.x)return a.y>b.y;
return a.x>b.x;
}
bool able(int i,int j){
if((r[i].x>r[j].x&&r[i].y>r[j].y)||(r[i].x>r[j].y&&r[i].y>r[j].x))return 1;
return 0;
}
int find(int i){
if(!pa[i])return i;
return find(pa[i]);
}
void print(int i){
printf(" %d",i);
if(!pa[i])return ;
print(pa[i]);
}
int main(){
int p=0,n,i,j,a,b,max=-0x3f3f3f3f;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&a,&b);
if(a<b)
r[i]=node(a,b,i);
else r[i]=node(b,a,i);
f[i]=1;
}
sort(r+1,r+1+n,cmp);
//for(i=1;i<=n;i++)printf("%d %d %d\n",r[i].num,r[i].x,r[i].y);
for(i=2;i<=n;i++){//因为此时处理的是排序后的数组,所以i,j并不代表其在原数组中的组数,为了方便记录路径,将i,j全部还原回原数组进行保存。
for(j=1;j<i;j++)
if(able(j,i)){
if(f[r[j].num]+1>f[r[i].num])
f[r[i].num]=f[r[j].num]+1,pa[r[i].num]=r[j].num;
else if(f[r[j].num]+1==f[r[i].num]&&r[j].num<pa[r[i].num])
pa[r[i].num]=r[j].num;
}
if(f[r[i].num]>max)max=f[r[i].num];
}
printf("%d\n",max);
for(i=1;i<=n;i++)//由于前面所存路径和值已经是以原数组下标来存,所以遍历时找到的第一个最大值即为字典序最小解。
if(f[i]==max){
p=i;
break;
}
printf("%d",p);
if(pa[p])//因为是最长下降子序列,所以不用倒序输出。
print(pa[p]);
printf("\n");
}