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;
}
}