#DP基础题#嵌套矩形(输出路径)

【基础算法】嵌套矩形

时间限制: 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");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值