百度之星astar-413-problem1

做这道题花了很多时间,所以没有长期的训练,想要在短时间内解决这种题目还是有一定的难度。


du熊的机器人
Description
du熊正在玩一个别人刚送给它的机器人。这个机器人只能在一个棋盘中行走,棋盘的左上角格子为(0, 0),右下角格子为(X, Y)。
du熊控制这个机器人从棋盘的左上角,走到右下角,再从右下角回到左上角。当机器人从左上角走到右下角的过程中,如果它当前所在格子为(x, y),则它只能走到(x+1, y)或(x, y+1)的格子;当机器人从右下角走回左上角的过程中,如果它当前所在的格子为(x, y),则它只能走到(x-1, y)或(x, y-1)的格子。并且du熊要求机器人从左上角走到右下角再走回左上角的整个过程中,最多经过同一个格子一次。
请你帮du熊计算出这个机器人一共有多少种不同的路线。
 
Input
输入的第一行为一个正整数T(0<T<=50),表示数据组数。
接下来的T行,每行有两个整数,分别表示X和Y。(1<=X,Y<=1000)
 
Output
对每组输入数据,输出一个整数,表示机器人不同的路线数量。
 
Sample Input
3
1 1
1 1000
3 4
 
Sample Output
2
2
100

问题分析:
群举是第一个直觉的做法,但题目里要求X,Y可以到1000,而X,Y达到10就已经是比较大的一个数,这个数目至少相当于从20的数中选10个出来。
第二想法是动态规划,因为每个点的运动使其构成树结构,但状态转移也不能很容易的找出来

定义S(m,n,x):满足某种条件的路径的数目,这些条件包括:
1、从坐标(0,0)出发,经过(m,n),终点是(0,1)
2、经过每个坐标最多一次
3、经过(x,0)
任一条逆时针可以走的路径,顺时针也满足题目要求 ,所以 2*S(m,n,0)就是题目要求的值。根据我们的定义,终点是(0,1),那么第一步一定是(0,0)->(1,0),S(m,n,0)等于S(m,n,1)。

接下来定义的状态转移:
终点是 (0,1),可以从两个方向到达(0,1)
1、最后一步(1,1)->(0,1)
这种情况下,满足条件的路径有这样的形式:(0,0)->(1,0)->...(m,n)->...->(1,1)->(0,1)
其数目等于 形式为 (1,0)->...(m,n)->...->(1,1)的所有满足条件的路径的数目,等于形式为(0,0)->...(m-1,n)->...->(0,1)的的所有满足条件的路径的数目,等于S(m-1,n,x-1)
2、最后一步(0,2)->(0,1)
由定义,一定存在某一步:(x,0)->(x,1),这个是显然的
对每个1<=x<=m,我们计算满足形式(0,0)->...->(x,0)->(x,1)->...-> (m,n)->...->(0,2)->(0,1)的所有路径的数目,定义这个数目为t(m,n,x)
所有经过 (x,0)形式满足(0,0)->...->(x,0)...->(m,n)->...->(0,2)->(0,1)的路径的数目为sum(t(m,n,x:m)
怎么求t(m,n,x)?观察可以发现,t(m,n,x)恰好等于S(m,n-1,x)

总结一下
S(m,n,x)= S(m-1,n,x-1) + sum(S(m,n-1,x:m)

边界条件:
我们总要要求起始点是(0,0)终点是(0,1),则S(m,0,x)=0,应为没有 终点(0,1)不存在
S(0,n,x) = 0,
S(0,0,0)=1,
S(0,1,0)=1,
这几个条件画个图都能简单的推出来

空间复杂度:O(M*M*N),时间复杂度 O(M*M*N)

最后一个问题,考虑到结算的结果特别大,状态转移矩阵可能要使用大数的数据结构

我的实现
#define AL 1000+1
long pathCount(const size_t M, const size_t N){
	long S[AL][AL][AL];
	for(size_t n = 0; n <= N; n++)
		S[0][n][0] = 0;
	for(size_t m = 0; m <= M; m++)
		for(size_t x = 0; x <= M; x++)
			S[m][0][x] = 0;
	S[0][0][0] = 1;
	S[0][1][0] = 1;
	for(size_t m = 1; m <= M; m++){
		for(size_t n = 1; n <= N; n++){
			long tmpS = 0;
			for(size_t x = m;x >= 1 ; x--){
				tmpS += S[m][n - 1][x];
				S[m][n][x] = S[m-1][n][x-1] + tmpS;
			}
			S[m][n][0] = S[m][n][1];
		}
	}
	return 2*S[M][N][0];
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值