【dp | 记忆化搜索】矩形嵌套

DAG上的动态规划

例题:矩阵嵌套   题目链接


【题意】:

只能两种摆法的矩阵,两个矩阵是否能嵌套关键在于:x,y为矩阵的长和宽。

那么嵌套的条件为:x<t.x&&y<t.y   ||   y<t.x && x <t.y

相当于重载这个结构体的 “小于号”


问题可以转化为:

多个矩阵  用小于号连接,找一个最长的情况。

【解法一】:

变相写成LIS,最长上升子序列

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef struct Node {
    int x,y;
    bool operator < (const Node &t) const { //重载小于号
        return (x<t.x&&y<t.y)||(y<t.x&&x<t.y);
    }
}Node;
Node c[N];
bool cmp(Node a,Node b){        //按照矩阵面积排序
    return a.x*a.y < b.x*b.y;
}
int dp[N];
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&c[i].x,&c[i].y),dp[i]=1;
        sort(c,c+n,cmp);
        int ans=1;
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++)
                if(c[j]<c[i]&&dp[i]<dp[j]+1)
                    dp[i]=dp[j]+1;
            if(dp[i]>ans)
                ans=dp[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

【解法二】:写成记忆化搜索:

第一步建图,然后用dfs往下搜索。

写成邻接矩阵的来搜索:

#include<bits/stdc++.h>
using namespace std;
typedef struct Node {
    int x,y;
    bool operator < (const Node &t) const {
        return (x<t.x&&y<t.y) || (y<t.x && x<t.y);
    }
}Node ;
const int N=1e3+10;
int G[N][N],n,dp[N],ans;
Node a[N];
int dfs(int x){
    if(dp[x]) return dp[x];
    int tmp=1;
    for(int i=1;i<=n;i++)
        if(G[x][i])
            tmp=max(dfs(i)+1,tmp);
    return dp[x]=tmp;
}
int main()
{
    int T;
    for(scanf("%d",&T);T;T--){
        ans=0;
        memset(G,0,sizeof(G));
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].x,&a[i].y);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if( a[i]<a[j] )
                    G[i][j]=1;
        for(int i=1;i<=n;i++)
            ans=max(ans,dfs(i));
        printf("%d\n",ans);
    }
    return 0;
}

紫书上提供了另类的写法:

个人感觉这个写法其实也不错。

int dfs(int x){
    int &ans = dp[x];
    if(ans>0) return ans;
    ans=1;
    for(int j=1;j<=n;j++){
        if(G[x][j]) ans=max(ans,dfs(j)+1);
    }
    return ans;
}

路径记录:

void print_ans(int i){
    printf("%d ",i);
    for(int j=1;j<=n;j++)
        if(G[i][j]&&dp[i]==dp[j]+1) {
            print_ans(j);
            break;
        }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值