题意:给了一个 n * n 的方格图,要从图的左上角走到右下角 ,每次只能向右或者向下走,走的格数为当前格子上的数字,问共有多少中走法。
一开始我看到之后觉得这题完全可以用记忆化搜索来做,dfs 一遍就能找出所有解,这是因为刚刚不久才做过那道记忆化搜索的题目,我用 dp + dfs 敲了一遍之后作死提交,果断AC```怎么可能想想都知道```TLE了,恩其实题目底下就有提示说是遍历所有的路可能会超时,但是我英语不好 orz 。
但事实上即使没有这个提示我也本就应该先考虑普通 DP ,因为上次的记忆化搜索是因为那张图是可以往上下左右四个方向走的,所以普通的顺序 dp 就会面临更新完别的格子之后自己又要更新的情况,但是这次只有向右和向下,所以完全应该第一个想到顺序 dp 的,这是我自己想复杂的,当然也要归咎于我对 dp 和记忆化搜索理解的还不够到位吧。
那么顺序的 dp 其实就非常简单了,dp [ i ] [ j ] 表示走到第( i , j )格的走法数, dp [ 1 ] [ 1 ] 是开始位置,所以标记为 1 ,之后依次遍历每一个点,如果该点 dp 值不为 0 ,即该点可以被走到 ,那么就根据它格子上的数字优化能从这个格点到达的格子的 dp 值。当然,要注意的是当格点数字为 0 的时候就不要对自己进行更新了,因为这样若右下角格子的数字是 0 的话,它就会连续优化自己,与其特判还不如一开始就不操作。优化方式就是将能到达的格点的 dp 值加上当前点的 dp 值。
1 #include<stdio.h> 2 #include<string.h> 3 int a[35][35]; 4 long long dp[35][35]; 5 int xx[2]={1,0}; 6 int yy[2]={0,1}; 7 int main(){ 8 int n; 9 while(scanf("%d",&n)!=EOF&&n!=-1){ 10 getchar(); 11 memset(dp,0,sizeof(dp)); 12 int i,j; 13 dp[1][1]=1; 14 for(i=1;i<=n;i++){ 15 for(j=1;j<=n;j++){ 16 char m; 17 scanf("%c",&m); 18 a[i][j]=m-‘0‘; 19 if(a[i][j]){ 20 if(dp[i][j]){ 21 int dx=i+a[i][j]*xx[0],dy=j+a[i][j]*yy[0]; 22 if(dx<=n&&dy<=n)dp[dx][dy]+=dp[i][j]; 23 dx=i+a[i][j]*xx[1];dy=j+a[i][j]*yy[1]; 24 if(dx<=n&&dy<=n)dp[dx][dy]+=dp[i][j]; 25 } 26 } 27 } 28 getchar(); 29 } 30 /* for(i=1;i<=n;i++){ 31 for(j=1;j<=n;j++){ 32 printf("%d ",dp[i][j]); 33 } 34 printf("\n"); 35 }*/ 36 printf("%I64d\n",dp[n][n]); 37 } 38 return 0; 39 }
时间: 2024-10-10 09:58:22