VJ链接
题意:
给出一个n*m的图,途中每个位置处的值代表该位置具有的能量数w(i,j)。从(1,1)开始移动,每次只能向下或向右走0~w(i,j)步。问从(1,1)到(n,m)有多少种移动方式?(结果对10000取模)
思路
1.新型移动情况:每次都可移动0~w(i,j)步,移动方向限制。新写法
2.求(1,1)到(n,m)的所有情况数,在(n,m)旁边位置的带到(n,m)的情况数是比较容易求出,利用递归先近后远。开记忆化数组记录该点到终点的情况总数。
3.移动时,每次dp[x][y]需要走遍(x,y)的所有出边才得到有效数据。需要枚举不同方向不同步数的所有情况,记录的dp[x][y]需要累加记录。
4.体现了dp思想,dp[x][y]最先得到有效值的一定是终点附近位置的点,然后递归返回上一层达到记录所有状态的目的。
新型移动方式
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int e[110][110],dp[110][110];
int n,m;
int dfs(int x,int y)
{
if(dp[x][y]>=0) return dp[x][y];
dp[x][y]=0; //开始累加,赋值0
for(int i=0;i<=e[x][y];i++)
for(int j=0;j<=e[x][y]-i;j++){
int nx=x+i;
int ny=y+j;
if(nx<=n&&nx>=1&&ny<=m&&ny>=1)
dp[x][y]=(dp[x][y]+dfs(nx,ny))%10000;
}
return dp[x][y];
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(dp,-1,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&e[i][j]);
dp[n][m]=1;//****搜索到终点时,开始返回实值
printf("%d\n",dfs(1,1));
}
return 0;
}