算法学习笔记六:dp

题目描述
在一个n*n的矩阵中,每个格子都有一个整数,PIPI位于矩阵的左上角,它想知道有多少条不同合法路线达到矩阵右下角。
行走规则如下:
(1)每次只能往下或往右走一步。
(2)格子中的整数表示从该点出发一步必须跨越的距离。

PS:对(1)和(2)条件的解释: 若此时在 (x,y) 并且格子上的数字为 k ,则下一步到达的位置为 (x+k,y)或 (x,y+k)
输入
多组数据
第一行为一个整数n,4<=n<=34.
接下来n行给出一个数字矩阵,0<=矩阵中元素<=9.
输出
对于每组数据输出一个整数,表示从左上角到右下角的不同路径数。
样例输入
4
2331
1213
1231
3110
4
3332
1213
1232
2120
5
11101
01111
11111
11101
11101
样例输出
3
0
7

本题用bfs会超内存,用递归会超时。。

先贴上递归

#include
#include
#include
using namespace std;
int count=0,n;
int map[35][35];
int dp(int x, int y)
{
	//cout<<"x="<
	if(x==n-1&&y==n-1)
	{
		count++;
		return 0; 
	}
	if(map[x][y]==0)
		return 0;
	if(x+map[x][y]<n)
	{
		dp(x+map[x][y],y);
	}
	if(y+map[x][y]<n)
	{
	//	cout<<"hi";
		dp(x,y+map[x][y]);
	}
		
 } 
int main()
{
	string ma[35];
	while(cin>>n)
	{
		int i,j; 
		for(i=0;i<n;i++)
			cin>>ma[i];
		for(i=0;i<n;i++)
			for(j=0;j<n;j++)
				map[i][j]=(int)(ma[i][j]-'0');
		count=0;
		i=dp(0,0);
		cout<<count<<endl;
	}
	return 0;
}

然后是正确写法:dp

动态规划思想:每一个点都由它上面点的和左边的点到达。因此遍历其上面的和左边的点。用dp[i][j]记录从起点到(i,j)有多少条路径。
初始将起点的dp设置为1,其他点的dp都置0,这样就可以确保只有来自起点的点才能被记录。
#include
#include
#include
using namespace std;
int main()
{
	int n;
	string ma[35];
	int map[35][35];
	while(cin>>n)
	{
		int i,j,k;
		long long dp[35][35];//dp[i][j]起点到(i,j)的路径数 
		memset(dp,0,sizeof(dp));
		for(i=0;i<n;i++)
			cin>>ma[i];
		for(i=0;i<n;i++)
			for(j=0;j<n;j++)
				map[i][j]=(int)(ma[i][j]-'0');
		dp[0][0]=1;	//起点为1 
		for(i=0;i<n;i++)
			for(j=0;j<n;j++)
			{
				for(k=0;k<j;k++)//先遍历从左边来的节点 
				{
					if(map[i][k]+k==j)
						dp[i][j]+=dp[i][k];//只有是来自起点的点才是不会加0 
				}
				for(k=0;k<i;k++)//遍历从上边来的节点 
				{
					if(map[k][j]+k==i)
						dp[i][j]+=dp[k][j];				
				}
			} 	
		cout<<dp[n-1][n-1]<<endl;
	}
	return 0;
}

你可能感兴趣的:(算法题)