首页 > ACM题库 > HDU-杭电 > hdu 2232 机器人的舞蹈-动态规划-[解题报告]C++
2014
01-04

hdu 2232 机器人的舞蹈-动态规划-[解题报告]C++

机器人的舞蹈

问题描述 :

一天四个不同的机器人a、b、c和d在一张跳舞毯上跳舞,这是一张特殊的跳舞毯,他由4个正方形毯子组成一个大的正方形毯子,一开始四个机器人分别站在4块毯子上,舞蹈的每一步机器人可以往临近(两个毯子拥有同一条边视为临近)的一个毯子移动或停留在原来的毯子(同一块毯子可以有多个机器人停留),这个时候机器人的制造者你想知道经过n步的移动有多少种方式可以让每个毯子上都有机器人停留。

输入:

对于每组数据输入一个整数n(0<=n<=100)

输出:

对于每组数据输入一个整数n(0<=n<=100)

样例输入:

1

样例输出:

9

HDU  2232 机器人的舞蹈

原题:http://acm.hdu.edu.cn/showproblem.php?pid=2232(如果您需要转载的话,请标明出处.womendeaiwoming-_-!)

 

第一次写解题报告,其中疏忽之处还请大家原谅并指出(如果有幸得您拜读的话),高手请无视,我在此班门弄斧一下^_^!

 

(废话)刚做这题时,对此类型题见到得很少(主要是我做的实在太少了……,呵,没见识),所以感觉实在是无从下手,摆渡之后却什么解题思路也无人谈及,而宸大哥只是写了代码却并无解释,实在不知其所云,n(<5)天之后经fanster28_大哥的点醒这才豁然开朗,所以将他的思路与各位分享一下。

 

正题:

     最关键的地方

我们可以设格子的位置编号为 
0 1
3 2
dp[n][i] 表示n步之后位置0的人停留在位置i的方案数
dp[n][0]=dp[n-1][0]+dp[n-1][1]+dp[n-1][3]
dp[n][1]=dp[n-1][1]+dp[n-1][0]+dp[n-1][2]
dp[n][2]=dp[n-1][1]+dp[n-1][3]+dp[n-1][2]
dp[n][3]=dp[n-1][0]+dp[n-1][2]+dp[n-1][3]

       看懂了没?如果没懂的话,再看解释一下:对照着上面的编号,可以走n步,那么一个机器人走过n步之后的方案总共有多少呢?我们可以这样来考虑,假设我们其中一个机器人a已经走到(n-1)步了,而它的目标是0号位置,那么在第n步时,停留在0号位置的方案的总数就可以由(n-1)步来确定了,因为(n-1)步与n步只有一步,可以选择走,当然也可以停留在原地,那么,也就是说,在(n-1)时总共有3个位置经过1步之后能够到达0号位置,分别为0号、1号和3 号,0号为停留在原地,1号是向左走1步,而3号的话,是向上走一步。用数学来表达的话,也就是上面的,dp[n][0]=dp[n-1][0]+dp[n-1][1]+dp[n-1][3],也就是在n步后,这个机器人到达0号位置的方案的总数,就是(n-1)步时在0号位置的方案数+在1号位置的方案数+在3号位置的方案数。一个机器人可以到达四个位置,于是有四个这样的式子。总共有四个机器人,这样的话,就有十六个。

        现在懂了上面的式子是怎么来的吧!那么我们再递推,往下递推!因为n步时的方案总数是由(n-1)步时的方案总数来确定,那么,(n-1)时的方案总数当然也就是由(n-2)的方案总数来确定,(n-2)由(n-3)来确定,……,(n-(n-2))也就是第2步自然也就由第1步时的方案数来确定了。      好了,到达了第1步,这是咱们用手指头可以算出来的吧,直接写上就行啦!至此便把所有的方案数都可确定 啦(又递推回去就得解了)。

 

        在我们知道开始在各号位置的机器人经n步之后到达各号位置的方案总数后,把所有可行的方案的数目加起来就行啦,机器人所在的位置合法的总共是4!=24种。因为一个位置上得要有一个机器人嘛!比如说,0号机器人在1号位置,1号机器人在0号位置,2号,3号机器人位置不变,这也是一种可行的方案。把所有这样合法的方案全部枚举出来也就24种(0号位置4个(四个机器人随便哪一个到0号位置上来都是可以的)*1号位置3个(因为有一个机器已经确定到了0号位置,它不可能再到1号位置上来)*2号位置2个*3号位置1个),也就是4*3*2*1=24

 

       每一种合法情况的方案总数就把每个机器所到达的位置的方案数相乘就得出来啦!最后把24情况全部加起来,得解!当然,n稍微大一点,方案就大得离奇了,所有题目也说要对9937取模

 

        总的来说,思想并不复杂,也不难。但如果说发现不了其中递推的关系的,做起来还当真无从下手。就算用手指头去算,走0步时是1 种,走1步时是9种,走2步是就达到了633种,这得把手指分多少片呢?  呵呵,很难想象只走2步却又这么多的方案吧!起码我是想不出来的!

 

 

        说明一下下面的代码:

int B[4][4]={

                   i/j 0 1 2 3
                  0 {1,1,0,1},
                  1 {1,1,1,0},
                  2 {0,1,1,1},
                  3 {1,0,1,1}
   };             这里是表示i行,j 列。 在n=1时在i号位置机器人停留在j号位置的方案数。拿i=0来说,表示在0号位置的机器人经过1步之后到达j的方案数,j=0,停留在原地,1种方案。j=1向右移动,1种方案。j=2,1步到不了,0种方案。j=3,向上移动,1种方案,即:1,1,0,1    上面的二维矩阵由此而推得。确定了n=1,由上述的推论,后面n>1的步数都是由n=1推出。所以我们需要把n=1的情况当作已知条件

        里面还有有关取模的问题:a*b%c=a%c*b%c,至于为什么可以这样,我就不在此累述了。

 

        水平不高,还有的地方说得不太明白或是说错了的,希望大家指出。

       

        下面的代码很乱

       

#include <iostream>

using namespace std;

int B[4][4]={						//n=1时各位置上的机器人到达各位置的方案数
				{1,1,0,1},
				{1,1,1,0},
				{0,1,1,1},
				{1,0,1,1}
			};

struct In{
	int A[4][4];
};

In a,b;               //a,b分别用来记录1步、2步……n步的方案数
void f(int n)		  //先把前1步求出给a,再由a求出后1步时的方案数后用b记,如此递归地求出n步
{
	int i,j;
	if(n==0)
	{
		for(i=0; i<4; i++)
		{
			for(j=0; j<4; j++)
			{
				b.A[i][j]=B[i][j];
			}
		}
	}
	else
	{
		f(n-1);
		for(i=0; i<4; i++)
		{
			for(j=0; j<4; j++)
			{
				a.A[i][j]=b.A[i][j];
				a.A[i][j]%=9937;			//数据过大,则对其取模
			}
		}
		if(n==1)
			return ;
		for(i=0; i<4; i++)        
		{
			b.A[i][0]=a.A[i][0]+a.A[i][1]+a.A[i][3];
			b.A[i][1]=a.A[i][0]+a.A[i][2]+a.A[i][1];
			b.A[i][2]=a.A[i][1]+a.A[i][2]+a.A[i][3];
			b.A[i][3]=a.A[i][0]+a.A[i][2]+a.A[i][3];
		}
	}
}

void Solve()
{
	int i,j,e,f,sum=0;
	for(i=0; i<4; i++)
	{
		for(j=0; j<4; j++)
		{
			for(e=0; e<4; e++)
			{
				for(f=0; f<4; f++)
				{
					if(i==j || i==e || i==f || j==e || j==f || e==f)    //每个位置上都得有一个机器人
						continue;
					sum+=((((((b.A[0][i]*b.A[1][j])%9937)*b.A[2][e])%9937)*b.A[3][f])%9937)%9937;   //防止越界,必须每两个方案相乘就得取模
					sum%=9937;
				}
			}
		}
	}
	cout<<sum<<endl;
}

int main()
{
	int n;
	while(cin>>n)
	{
		f(n);
		Solve();
	}
	return 0;
}

解题转自:http://blog.csdn.net/womendeaiwoming/article/details/5806700


  1. 这道题目的核心一句话是:取还是不取。
    如果当前取,则index+1作为参数。如果当前不取,则任用index作为参数。

  2. [email protected]