一、DAG的定义
DAG为一个有向无环图,任意一条边有方向,但是不存在环路。
A→B→C即为有向无环图。
二、搜索与记忆化搜索
经典例题:有N个矩形,每个矩形可以用ab来描述,a和b分别为矩形的长与宽。矩形X可以嵌套在矩形Y中当且仅当a<a1&&b<b1或者a<b1&&b<a1(相当于旋转90°)时成立,一个只能嵌套一个,你的任务是选出最多可以嵌套的矩形。
1.题解:(暴力搜索思想DFS)
首先需要一个结构体:
struct node{
int x,y;
};
node node1[150]//假设n最多有150个
int vis[400][400];//用来标记关系的数组
可以把没一个矩形都看作一个点,如果X包含Y,则vis[X][Y]=1,根据DFS的思想,先以随机一个点为起始点开始比较,如果vis[i][k]走完没有1,则说明i不能继续走了,就要return。根据这个思想,可以让程序直接走到最后,令步数=1,往上回溯时,步数+1,每次比较都找出对应的最大的步数。所以我们首先需要标记,标记代码:
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&node1[i].x,&node1[i].y);
for(int i=0;i<n;i++)
for(int k=0;k<n;k++)
{
if(node1[i].x>node1[j].x&&node1[i].y>node1[j].y)
vis[i][j]=1;
if((node1[i].y>node1[j].x&&node1[i].x>node1[j].y))
vis[i][j]=1;
}
然后需要进行DFS:
int DFS(int u,int n)//n为矩形数量
{
ll maxx=1;
for(int i=0;i<n;i++)
if(vis[u][i])//如果u矩形可以包含i矩形
maxx=max(maxx,DFS(i,n)+1);//对矩形i继续搜索,看他是否包含了其他矩形。
return maxx;
}
//这个程序走到无路可走时,就回回溯,毎回溯一次maxx+1,所以每一个节点都会有一个maxx,最后的结果就是maxx
上述程序是以任一点作为起始点,为保证答案的绝对正确性,需要将所有的起始点,都遍历一遍看一看。
所以在主函数中:
ll maxx=1;
for(int i=0;i<n;i++)
maxx=max(maxx,DFS(i,n));
printf("%lld",maxx);
}
maxx即为最后最大值
2.记忆化搜索
就此题而言,当4 1 1 2 2 3 3 3 3时,应该是3,当以1为出发点时,每一个节点都会走,并且每一个节点都会有他自己的maxx(维护的权值),所以,我们可以用一个数组记录一下,每一个点的权值即maxx,当权值为0时,说明这个点之后的已经都走过了,无需再走,直接return当前的权值,然后进行下一步。此方法叫做记忆化搜索:
ll ans=0;
ll dp[150];
ll DFS(int u,int n)
{
ans++;//次数检测,用来比较搜索与记忆化搜索的复杂度,无需注意。
if(dp[u])//如果不等于0,说明有权值,说明之后的节点都走过,且最大值都计算出开了。
return dp[u];//直接return这个节点的权值
ll maxx=1;
for(int i=0;i<n;i++)
if(vis[u][i])//如果u矩形可以包含i矩形
maxx=max(maxx,DFS(i,n)+1);
return dp[u]=maxx;//没走过return重新得到的权值
}
而且我们也可以很清楚用ans记录步数,发现原本是11,现在只需要9,当数据大时肯定会减少很多。
三、动态规划
关于以上问题我们可以首先对矩形进行排序:
bool cmp(node a,node b)
{
if(a.x==b.x)
return a.y<b.x;
return a.x<b.x;
}
排序后,我们可以想,矩形i可以嵌套的矩形数量等于他嵌套的矩形可以嵌套矩形的数量+1,最多的话应在这些选择之中加个max选出最大值。
int dp[150];
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&node1[i].x,&node1[i].y);
sort(node1,node1+n,cmp);
for(int i=0;i<n;i++)
{
dp[i]=1;//第一个矩形肯定能嵌套一个就是他自己。
for(int k=0;k<i;k++)
{
if(node1[i].x>node1[k].x&&node1[i].y>node1[k].y)
dp[i]=max(dp[i],dp[k]+1);//他能嵌套的矩形数量,=,他嵌套的矩形能嵌套矩形的数量+1。
if(node1[i].y>node1[k].x&&node1[i].x>node1[k].y)
dp[i]=max(dp[i],dp[k]+1);
}
}
//通过这两个for循环,就把从0-n序号的矩形,所能包含的最大矩形数量找出来了。
//用max函数求出最大值就好。
int maxx=1;
for(int i=0;i<n;i++)
maxx=max(maxx,dp[i]);
printf("%d",maxx);
}
方程 dp[i]=max(dp[i],dp[k]+1)称为状态转移方程
四、总结
1.此类记忆化搜索与动态规划只是用与DGA,也就是用图来表示的话,应该是一个有向无环图。
2.记忆化搜索与动态规划类似,都是将每一个节点的最大值保存起来,作为他的权值,最后输出。
3.加油,继续加油!