DAG模型–矩形镶嵌
n个矩形排成一行,找出做多的矩形,使左边的矩形可以镶嵌在右边的矩形中。矩形满足镶嵌也就是左边长宽a,b,右边长宽c,d构成:a<c且b<d 或者 b<c且a<d
,
思路:可以将两矩形之间可以镶嵌转化为两点之间可单向通过的结构。将n个矩形转化为无环单向图,再用动态规划的思想设一个状态d(i),也就是从i点出发最长的路径状态。
之后就可以设出状态转移方程:d(i)=max(1,dp(j)+1)
当然记得记忆化搜索可以大大减少时间复杂度,所以状态d(i)初始话标记一下0,在搜索时只要判断,若大于0,直接就可以把之前算过了的答案回溯回去,减少了重复计算的过程。
之后在所有的状态d(i)中找出路径最长的,但是题目要求要寻出编号字典序最小的,所以答案若有多个,就找出i最小的。
找到的这个i,就是起点字典序最优且最小的,在设一个函数就可以将他后面的点找出来。
注意,后面的点应该满足:可以走通(可以镶嵌),最优选项
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 105
struct nec
{
int c;
int k;
};
struct nec rect[maxn];
int n,d[maxn]={
0};
int maxx=0,maxi=0,graph[maxn][maxn]={
0};
void build()
{
int i;
for(i=1;i<=n;i++)
{
cin>>rect[i].c>>rect[i].k;
}
}
int judge(int i,int j)
{
if((rect[i].c<rect[j].c&&rect[i].k<rect[j].k)||(rect[i].c<rect[j].k&&rect[i].k<rect[j].c))
return 1;
return 0;
}
int dp(int i)
{
int j;
int& ans=d[i];
if(ans>0)
return ans;
ans=1;
for(j=1;j<=n;j++)
{
if(graph[i][j]==1)
{
ans=max(ans,dp(j)+1);
}
}
return ans;
}
void print_ans(int i)
{
int j;
cout<<i<<" ";
for(j=1;j<=n;j++)
{
if(graph[i][j]==1&&d[i]==d[j]+1)
{
print_ans(j);
break;//很重要
}
}
}
int main()
{
int i,j;
cin>>n;
build();
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(i==j)
continue;
graph[i][j]=judge(i,j);
}
}
for(i=1;i<=n;i++)
{
dp(i);
}
for(i=1;i<=n;i++)
{
if(d[i]>maxx)
{
maxx=d[i];
maxi=i;
}
}
cout<<"max="<<maxx<<endl;
print_ans(maxi);
cout<<endl;
return 0;
}