对记忆化搜索(ms)和动态规划(dp)的深入理解

匿名 (未验证) 提交于 2019-12-03 00:27:02




这样就做到了数组的每个值只计算了一次,不会有多余的时间消耗。

还有一点!记住ms型dfs就必须是int型的了!! 不要在用bool或者void了!

下面送上记忆化搜索的fib求解的部分代码:

#include<iostream> using namespace std; const int MAX = 10000+5; int fib[MAX]; int dfs(int n) {//  	if(fib[n]!=-1) return fib[n]; 	 	return fib[n]=dfs(n-1)+dfs(n-2); 	 } int main() { 	fib[1]=fib[2]=1; 	for(int i = 2; i<MAX; i++) { 		fib[i]=-1; 	} 	dfs(MAX-1);//别写成了MAX,那样输出的全是-1  	for(int i = 1; i<=50; i++) { 		printf("%d ",fib[i]); 		if(i%5==0) {  			printf("\n");  		} 	} 	return 0 ;  } 

输出结果:

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 -1323752223 512559680 -811192543 -298632863
从中也容易看出来,fib数列增长还是很快的!(通项可以用母函数表示出来!但是目前对母函数尚未学精,暂不做讨论)


下面是一个很值特研究的问题:

为什么说能用dp的都能用ms,但是反之不立。(至少我是这么认为的)

在fib中,你会发现写记忆化搜索像个傻子一样自取麻烦,直接dp递推多简单,多此一举。但之所以在fib中ms和dp如此相似是因为fib的顺序是固定的!有规律的!所以体现不出ms的用处来!

再看一道题比如滑雪,你如果用dp,必须要排序!然后按照排序的顺序(那道题是按照高度排序的)从小到大递推!原因也很简单,因为dp[i][j]可能需要用到四周的值!且dp有个特点,我既然要用你,那么你的值,比如要是已经确定的值(就是不会再更新这个值了),我给他取个名叫完成值,并给他一个特点,那就是,你如果是完成值,那么你将不会再被更新了,也就是,对这个数据,只有读的功能,没有写的功能。也就是说,比如if(i,j右边那个点的高度(即i,j+1)<当前i,j坐标的高度),那么更新dp[i][j],并且dp[i][j]也是完成值了!(通过判断是不是-1来确定是否是完成值,因为最开始初始化成-1),而如果i,j右边那个点的高度(即i,j+1)<当前i,j坐标的高度,那就无所谓i,j+1是不是完成值了,,,反正你也不去读这个数据(刚刚说过了对完成值只能读不能写!)所以你需要用到的值,都是高度比你小的值,这也是为什么需要进行按照高度从小到大进行排序,并且递推的时候,只能按照这个顺序进行递推!

上面一段是你如果用dp的情况,而如果你用的是ms,情况将没这么复杂,不需要排序!不需要按照一定顺序递推!而只需要上面提到的两条关键的语句块,就解决的所有事情!具体还是需要自己体会的。、。。

下面贴上滑雪的ms代码:

#include<iostream> #include<cstdio> #include<algorithm> using namespace std;  int r,c; int maze[105][105]; int dp[105][105]; void init () { 	for(int i = 1; i<=104 ; i++) { 		for(int j = 1 ; j<=104 ; j++) { 			dp[i][j]=-1; 		} 	} } bool ok(int x,int y){ 	if(x<=r&&x>0&&y<=c&&y>0) return true; 	else return false; }  int dfs(int x,int y) { 	if(dp[x][y]!=-1) { 		return dp[x][y]; 	} //	if(x==0||y==0) return 0 ; 	int flag=0; 	int next[4]={0,0,0,0}; 	if(maze[x+1][y]<maze[x][y]&&ok(x+1,y)) { 		next[0]=dfs(x+1,y); 		flag=1; 	} 	if(maze[x][y+1]<maze[x][y]&&ok(x,y+1)) { 		next[1]=dfs(x,y+1); 		flag=1; 	} 	if(maze[x-1][y]<maze[x][y]&&ok(x-1,y)) { 		next[2]=dfs(x-1,y); 		flag=1; 	} 	if(maze[x][y-1]<maze[x][y]&&ok(x,y-1)) { 		next[3]=dfs(x,y-1); 		flag=1; 	} 	if(flag==0) return dp[x][y]=0; 	return dp[x][y]=1+*max_element(next,next+4); } int main() { 	 	cin >> r>>c; 	int maxx=0; 	init(); 	for(int i=1; i<=r; i++) { 		for(int j = 1 ; j<=c ; j++) { 			scanf("%d",&maze[i][j]); 		} 	} 	for(int i=1; i <= r ; i++) { 		for(int j = 1 ; j <= c ; j++) { 			maxx=max(maxx,dfs(i,j)); 		} 	} 	cout << maxx+1<<endl; 	return 0 ;  } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!