码迷,mamicode.com
首页 > 其他好文 > 详细

HDU ACM 2232 机器人的舞蹈

时间:2015-06-02 09:25:12      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   编程   

#include<iostream>
using namespace std;

int base[4][4]={           //初始状态
	{1,1,0,1},
	{1,1,1,0},
	{0,1,1,1},
	{1,0,1,1}};

int a[2][4][4];           //滚动数组

void f(int n)
{
	int i,j;

	if(n==0)
	{
		for(i=0;i<4;i++)
			for(j=0;j<4;j++)
				a[1][i][j]=base[i][j];
	}
	else
	{
		f(n-1);
		for(i=0;i<4;i++)
			for(j=0;j<4;j++)
				a[0][i][j]=a[1][i][j]%9937;

    	if(n==1)
	    	return ;
    	for(i=0;i<4;i++)
		{
	    	a[1][i][0]=a[0][i][0]+a[0][i][1]+a[0][i][3];
	    	a[1][i][1]=a[0][i][0]+a[0][i][2]+a[0][i][1];
	    	a[1][i][2]=a[0][i][1]+a[0][i][2]+a[0][i][3];
	    	a[1][i][3]=a[0][i][0]+a[0][i][2]+a[0][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+=(((((a[1][0][i]*a[1][1][j])%9937)*a[1][2][e])%9937)*a[1][3][f])%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的详细分析。

正题:

     最关键的地方

我们可以设格子的位置编号为  
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,至于为什么可以这样,我就不在此累述了。

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

        下面的代码很乱

  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. int B[4][4]={                       //n=1时各位置上的机器人到达各位置的方案数  
  6.                 {1,1,0,1},  
  7.                 {1,1,1,0},  
  8.                 {0,1,1,1},  
  9.                 {1,0,1,1}  
  10.             };  
  11.   
  12. struct In{  
  13.     int A[4][4];  
  14. };  
  15.   
  16. In a,b;               //a,b分别用来记录1步、2步……n步的方案数  
  17. void f(int n)         //先把前1步求出给a,再由a求出后1步时的方案数后用b记,如此递归地求出n步  
  18. {  
  19.     int i,j;  
  20.     if(n==0)  
  21.     {  
  22.         for(i=0; i<4; i++)  
  23.         {  
  24.             for(j=0; j<4; j++)  
  25.             {  
  26.                 b.A[i][j]=B[i][j];  
  27.             }  
  28.         }  
  29.     }  
  30.     else  
  31.     {  
  32.         f(n-1);  
  33.         for(i=0; i<4; i++)  
  34.         {  
  35.             for(j=0; j<4; j++)  
  36.             {  
  37.                 a.A[i][j]=b.A[i][j];  
  38.                 a.A[i][j]%=9937;            //数据过大,则对其取模  
  39.             }  
  40.         }  
  41.         if(n==1)  
  42.             return ;  
  43.         for(i=0; i<4; i++)          
  44.         {  
  45.             b.A[i][0]=a.A[i][0]+a.A[i][1]+a.A[i][3];  
  46.             b.A[i][1]=a.A[i][0]+a.A[i][2]+a.A[i][1];  
  47.             b.A[i][2]=a.A[i][1]+a.A[i][2]+a.A[i][3];  
  48.             b.A[i][3]=a.A[i][0]+a.A[i][2]+a.A[i][3];  
  49.         }  
  50.     }  
  51. }  
  52.   
  53. void Solve()  
  54. {  
  55.     int i,j,e,f,sum=0;  
  56.     for(i=0; i<4; i++)  
  57.     {  
  58.         for(j=0; j<4; j++)  
  59.         {  
  60.             for(e=0; e<4; e++)  
  61.             {  
  62.                 for(f=0; f<4; f++)  
  63.                 {  
  64.                     if(i==j || i==e || i==f || j==e || j==f || e==f)    //每个位置上都得有一个机器人  
  65.                         continue;  
  66.                     sum+=((((((b.A[0][i]*b.A[1][j])%9937)*b.A[2][e])%9937)*b.A[3][f])%9937)%9937;   //防止越界,必须每两个方案相乘就得取模  
  67.                     sum%=9937;  
  68.                 }  
  69.             }  
  70.         }  
  71.     }  
  72.     cout<<sum<<endl;  
  73. }  
  74.   
  75. int main()  
  76. {  
  77.     int n;  
  78.     while(cin>>n)  
  79.     {  
  80.         f(n);  
  81.         Solve();  
  82.     }  
  83.     return 0;  
  84. }  


HDU ACM 2232 机器人的舞蹈

标签:c   c++   acm   算法   编程   

原文地址:http://blog.csdn.net/a809146548/article/details/46318453

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!