有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内。如果有多解,矩形编号的字典序应尽量小。
很显然,这样的矩阵嵌套关系是一种大套小,而小不能套大的情形,所以说这里的嵌套都是单向的,矩阵间的嵌套也不可能出现循环的情形,综合起来看就是DAG(directed acyclic graph)有向无环图的一种。
DAG既然是一个图,那么肯定要有它的存储方案,邻接矩阵或是链式前向星。而遍历这个图就需要一些方式,比如说dfs这样的深度搜索算法,而记忆化深度搜索是动态规划算法的另一种表现形式,可以减少重复计算,降低复杂度。
所以对于这个题,建好图然后进行记忆化搜索就可以解出,如果要输出字典序最小方案,只需要从最优方案的终下标按照一定规律深搜回去并输出即可。
#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 2000;
inline ll lldcin()
{
ll tmp = 0, si = 1;
char c;
c = getchar();
while (c > '9' || c < '0')
{
if (c == '-')
si = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
tmp = tmp * 10 + c - '0';
c = getchar();
}
return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
struct rec
{
ll length, width;
}recs[124124];
ll relationships[1200][1200], dp[1200];
ll dfs(ll current, ll limit)//记忆化搜索的函数
{
ll &tmp = dp[current];//使用引用符号是为了变更tmp值的同时改变dp[current]的值
if (tmp)
return tmp;
else
{
tmp = 1;
for (int i = 1; i <= limit; i++)
{
if (relationships[current][i])//如果存在嵌套关系,继续深搜。
tmp = max(tmp, dfs(i, limit) + 1);//取最优解
}
return tmp;
}
}
void print_ans(ll current, ll limit)
{
for (int i = 1; i <= limit; i++)
{
if (relationships[current][i] && dp[current] == dp[i] + 1)//如果存在嵌套关系并且i矩形的嵌套关系可以由现状直接推出
{
print_ans(i, limit);
break;
}
}
cout << current << " ";//回溯后输出
}
int DETERMINATION()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n;
cin >> n;
for (int i = 1; i <= n; i++)
{
ll tmp1, tmp2;
cin >> tmp1 >> tmp2;
if (tmp1 < tmp2)
swap(tmp1, tmp2);
recs[i].length = tmp1, recs[i].width = tmp2;//直接把矩形旋转到同样的长宽摆放方式
}
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)//建图,这个必须双向判断,因为第一个if只能判断单减样例,第二个if只能判断单增样例。
{
if (recs[i].length > recs[j].length&&recs[i].width > recs[j].width)
relationships[i][j] = 1;
else if (recs[i].length < recs[j].length&&recs[i].width < recs[j].width)
relationships[j][i] = 1;
}
}
//for (int i = 1; i <= n; i++)
//{
// for (int j = 1; j <= n; j++)
// cout << relationships[i][j] << " ";
// cout << endl;
//}
ll ans = 0, mk = 0;
for (int i = 1; i <= n; i++)
{
ll t = dfs(i, n);
if (t > ans)
{
ans = t;
mk = i;
}
}
print_ans(mk, n);
cout << endl;
cout << ans << endl;
return 0;
}