hdu--1978--记忆化深度搜索||递推
这题 我开始的做法是 记忆化搜索 但是tm地竟然tle了。。。很想不通 因为数据很小啊 就100 虽然方案的总数可能会很大..
然后 我就去百度 记忆化搜索 看下是不是我用错方法了 事实证明 我虽然没有用错 但还是 学到了很多=-=、
其实 我很早以前 也看过关于 记忆化搜索的一些介绍 但是 并没有太多感觉 并不是那些作者写的不好 而是我的水平没到 感受不了。。
很多东西会在不知不觉中提升~
我想 将我读的这篇介绍 传到这篇博客里来 似乎只能上传照片和视频=-= 那我给个链接吧 传送
虽然里面的代码不是用C/C++写的 但其实不会太影响我们的阅读 重点是对于 动态规划 与 搜索思想的理解
------------touch me
然后 我继续回过头来检查自己的TLE代码 我去discuss里看了下别人的讨论 发现很多人用的都是 递推式的动态规划做的 看到了一个和我用相同的记忆化深搜做的
and then i got it
我对于maze[i][j]的处理太懒了...耗了太多时间..
我将tle与改后AC代码都放上来吧
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 int n , m; 6 const int mod = 10000; 7 const int size = 110; 8 int maze[size][size]; 9 int dp[size][size]; 10 bool vis[size][size]; 11 12 int dfs( int x , int y ) 13 { 14 if( x==n && y==m ) 15 return 1; 16 if( vis[x][y] ) 17 return dp[x][y]; 18 if( maze[x][y]==0 ) 19 return 0; 20 for( int i = x ; i<=n ; i++ ) 21 { 22 for( int j = y ; j<=m ; j++ ) 23 { 24 if( (i-x + j-y) > maze[x][y] || x==i && y==j ) 25 continue; 26 else 27 { 28 dp[x][y] += dfs(i,j); 29 if( dp[x][y]>=mod ) 30 dp[x][y] %= mod; 31 } 32 } 33 } 34 vis[x][y] = true; 35 return dp[x][y]; 36 } 37 38 int main() 39 { 40 cin.sync_with_stdio(false); 41 int t , ans; 42 while( cin >> t ) 43 { 44 while( t-- ) 45 { 46 memset( vis , false , sizeof(vis) ); 47 memset( dp , 0 , sizeof(dp) ); 48 cin >> n >> m; 49 for( int i = 1 ; i<=n ; i++ ) 50 { 51 for( int j = 1 ; j<=m ; j++ ) 52 { 53 cin >> maze[i][j]; 54 } 55 } 56 ans = dfs(1,1); 57 cout << ans << endl; 58 } 59 } 60 return 0; 61 }
*** 其实 vis数组 是可以不写的 因为完全可以通过if( dp[ x ] [ y ])return dp[x][y]来做到 但是我习惯上 有时候会写上它 有助于理解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 int n , m; 6 const int mod = 10000; 7 const int size = 110; 8 int maze[size][size]; 9 int dp[size][size]; 10 bool vis[size][size]; 11 12 int dfs( int x , int y ) 13 { 14 if( x==n && y==m ) 15 return 1; 16 if( vis[x][y] ) 17 { 18 return dp[x][y]; 19 } 20 if( maze[x][y]==0 ) 21 return 0; 22 for( int i = 0 ; i<=maze[x][y] ; i++ ) 23 { 24 for( int j = 0 ; j+i<=maze[x][y] ; j++ ) 25 { 26 if( !(i+j) || x+i>n || y+j>m ) 27 continue; 28 else 29 { 30 dp[x][y] += dfs( x+i,y+j); 31 if( dp[x][y]>=mod ) 32 dp[x][y] %= mod; 33 } 34 } 35 } 36 vis[x][y] = true; 37 return dp[x][y]; 38 } 39 40 int main() 41 { 42 cin.sync_with_stdio(false); 43 int t , ans; 44 while( cin >> t ) 45 { 46 while( t-- ) 47 { 48 memset( vis , false , sizeof(vis) ); 49 memset( dp , 0 , sizeof(dp) ); 50 cin >> n >> m; 51 for( int i = 1 ; i<=n ; i++ ) 52 { 53 for( int j = 1 ; j<=m ; j++ ) 54 { 55 cin >> maze[i][j]; 56 } 57 } 58 ans = dfs(1,1); 59 cout << ans << endl; 60 } 61 } 62 return 0; 63 }
稍微 解释下 有助于 初学者的我们来理解:
因为是 深搜 所以这是递归的 我们可以将dp[ x ] [ y ]看成在N * M的地图里有多少种方式从(N,M)这个终点走到(X,Y)这个点 然后你可能会遇到dp[ x1 ] [ y1 ]与dp[ X2 ][ y2]都需要求得dp[ x3 ][ y3 ]那么我们只要将这个值给保存下来 在(x1,y1),(x2,y2)需要的时候 直接给它们就可以了 这里就有着DP对于重叠子问题的处理 而递归又是深搜的体现
这里 有一个边界注意下 就是(N,M) 当你搜索到这个点时 就可以看成是 递归出口了 然后直接返回一个 1 就可以了
我们再来讲下 递推的处理
这就和递归 完全2个方向 可以这样想 一个是 自底向上 一个是顶向下 dp[ x ][ y ]就变成了是N*M的地图里有多少种方式从(1,1)走到(x,y)这个点
其余多的解释 我也讲不来了 并且 我不确认 我以上所讲 都是正确的 都是我自己的理解 欢迎 探讨=-=
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 const int size = 110; 6 const int mod = 10000; 7 int maze[size][size]; 8 int dp[size][size]; 9 10 int main() 11 { 12 cin.sync_with_stdio(false); 13 int n , m , t; 14 while( cin >> t ) 15 { 16 while( t-- ) 17 { 18 cin >> n >> m; 19 for( int i = 1 ; i<=n ; i++ ) 20 { 21 for( int j = 1 ; j<=m ; j++ ) 22 { 23 cin >> maze[i][j]; 24 } 25 } 26 memset( dp , 0 , sizeof(dp) ); 27 dp[1][1] = 1; 28 for( int i = 1 ; i<=n ; i++ ) 29 { 30 for( int j = 1 ; j<=m ; j++ ) 31 { 32 for( int p = 0 ; p<=maze[i][j] ; p++ ) 33 { 34 for( int q = 0 ; p+q<=maze[i][j] ; q++ ) 35 { 36 if( !(p+q) || p+i>n || q+j >m ) 37 continue; 38 else 39 { 40 dp[i+p][j+q] += dp[i][j]; 41 if( dp[i+p][j+q]>=mod ) 42 dp[i+p][j+q] %= mod; 43 } 44 } 45 } 46 } 47 } 48 cout << dp[n][m] <<endl; 49 } 50 } 51 return 0; 52 }
其实我觉得 刚接触dfs的时候 并不是那么容易理解 或者 像我这种迟钝点的 我写了下面一段小小的代码 有助于理解=-=
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> using namespace std; void dfs( char ch,int x ) { char zh = ch + 1; x+=2; for( int i = x ; i<=10 ; i+=2 ) { cout << ch << " " << i << endl; dfs(zh,i); } } int main() { dfs('a',1); }
today:
在虎扑看到了个很有感触的帖子...选了里面一些jr的回帖 当做today:
和前女友异地恋,她经常主动打电话给我,有一天我嫌烦了,就对她说以后没事少给我打电话。她委屈地对我说:“想到你一个人在外地工作,身边一个朋友都没有,一个人吃饭,住房,我就很心疼,所以才老打电话给你。“
分手的那天:“我觉得我十年后肯定不是这样,但是你十年后还是现在这个样子。”
每天一点点努力,就是不想让下一个女人再说这种话。
她:“在网吧?有件事想和你说。”
我:“现在没空,晚上回你。“
大二在宿舍:
她:“在睡觉呢?今天没点名,不过明天早上上课把你的看电影带过来给我看看好吗?”
我:“哦,明天有课?”
第二天继续睡觉。。。
大三夜里失眠:
我短信:“我还有机会吗?”
她回复:“黄花菜都凉了!”
毕业一年:
她:“我下月结婚,你能来吗?”
我:“这几个月在外派啊,估计赶不回来。”
毕业两年:
她:“帮我给宝宝取个名字吧,男孩。”
我:“哈,读书少,不会取啊。大宝?”
她:“你个弱智,永远不上心。”
啪,挂掉。
![](http://b1.hoopchina.com.cn/post/smile/icon_sad17.gif)
![](http://b1.hoopchina.com.cn/post/smile/icon_sad17.gif)
大哥们,我承认我当初比较混蛋,更多的是她是女神,我是穷小子,想得多,自卑。当黄花菜凉的时候人家就已经有男朋友了,你们想让我怎么办,去挖墙脚吗?我一直知道自己辜负了她,所以更不想去打扰她的生活,至于之后的交流也更多的是朋友之间的互动。
另外,当初有点文艺,快临产的时候她知道是个男孩,名字一直定不下来,所以问了下我,真没有其他的意思。
也奉劝JRS,凡事往前看,有好女孩要大胆追、要珍惜。记事起就哭过有数的四次,黄花菜就是其中之一!
现在想起来这句话还是很心酸