How many ways
这个题的主要思路是DP
其实整体的思路——我为人人
设立f[i][j],即为从起点到第i行第j列位置的方案数
那么我们需要考虑:
当已经走到了i,j这个点,那么我将用这个格子的能量(num[i][j])。
因为方向是只能向右向下(不限定方向你还能求?),所以我们需要枚举新的点x,y。
这个点x,y是需要满足能够从i,j到达,没有越界,并且要看能量够不够让你走得到(不能让你走,你还能往下走?),或者是原地踏步
那么公式很显而易见了:f[x][y]=(f[x][y]+f[i][j])%10000; 即是把f[i][j]的方案数传递给f[x][y]。
以上就是一个点的“我为人人”策略,然后就继续跑下一个点,直到跑到最后一个点就停止。
初始值的话,就是起点赋值为1。
注意:f数组要清0,随时mod很香噢,多注意别越界,或者做了不该做的事情(类似原地踏步,你还在死命的算)
时间复杂度:
(1)首先,你需要枚举i,j。所以是这个地方是O(n2)
(2)其次,你还要在这个枚举里面再枚举一个点x,y,所以这个地方也是O(n2)(估大,实际远远小于这个数)
那么整个算法的时间复杂度即为O(n2)×O(n2)=O(n4),也就O(1004)=O(100,000,000)能过,当然也远远没有这么久
参考算法程序段(不要问我为什么不给全部程序,只是因为防止ctrl+c和ctrl+v,而且给你主要程序段已经很香了)
1 f[1][1]=1; 2 for(i=1;i<=n;i++) 3 { 4 for(j=1;j<=m;j++) 5 { 6 if(i==n&&j==m)continue; 7 f[i][j]%=10000; 8 for(x=i;x<=num[i][j]+i&&x<=n;x++) 9 for(y=j;y<=num[i][j]+j&&y<=m;y++) 10 { 11 if(x==i&&y==j)continue; 12 if(num[i][j]>=x-i+y-j) 13 f[x][y]=(f[x][y]+f[i][j])%10000; 14 } 15 } 16 } 17 f[n][m]%=10000; 18 printf("%d\n",f[n][m]);
代码自行理解吧…… 其实花点时间,也是蛮好理解的
浙公网安备 33010602011771号