历届试题格子刷油漆

问题描述
  X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。


  你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
  比如:a d b c e f 就是合格的刷漆顺序。
  c e f d a b 是另一种合适的方案。
  当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入格式
  输入数据为一个正整数(不大于1000)
输出格式
  输出数据为一个正整数。
样例输入
2
样例输出
24
样例输入
3
样例输出
96
样例输入
22
样例输出
359635897
 
  题中所提示的是动态规划
这个题就是先找规律分析,
   当从角落开始时,  就三种情况 :
       例如c[0][1]开始到c[1][1]结束,那么设从某一个角落开始到它邻近的角落结束   的个数是a[n],那么an=2*a[n-1],
       从一个角落先经过邻近的角落在 经过剩下的   设从一个角落开始遍历的所有方法个数是 b[n],那么  这样的方式总共个数为2*b[n-1]
       如果从一个角落开始,中间过程(除了第二个经过)经过它邻近的角落,那么肯定是第三个经过,(画图分析得出),那这种方式总共的个数是2*2*b[n-2]
  sum=an+2*b[n-1]+2*2*b[n-2]     
  sum=4*sum   (因为有四个角落)
  
  然后再分析从中间开始的,设第i列 某一行的一个格子开始    肯定是先遍历左边再右边,或者先右边再左边,肯定还要经过这一列的另一行的这个格子,
  所以先左边 看做是上面三种情况的第一种,右边是第二种  就是说 a[i]*2*b[n-i],先右边是第一种,左边是第二种 就是说a[n-i+1]*2*b[i-1]  
  每一列有两行,所以说是2 *(a[i]*2*b[n-i]+a[n-i+1]*2*b[i-1] )
  对每一列遍历累加 最后加上角落的sum,就是最后结果
 
 
 
 
 
 
#include  <iostream>
#define MOD 1000000007
using namespace std;
int long long  a[1003],b[1003];
int main()
{
    int n;
    long long int sum=0;
    cin>>n;
    if (n==1)
    {
    cout<<2;
    return 0;
}

    a[1]=1;
    for (int i=2;i<=n;i++)
     a[i]=2*a[i-1]%MOD;
    b[1]=1;b[2]=6;
    for (int j=3;j<=n;j++)
    {
        b[j]=(a[j]+2*b[j-1]+4*b[j-2])%MOD;
    }
    sum=4*b[n];
    for (int i=2;i<=n-1;i++)
   sum=(sum+2*(2*a[i-1]*2*b[n-i]%MOD+2*a[n-i]*2*b[i-1]%MOD)%MOD)%MOD;
     cout<<sum;

}

 

下面是一开始我做的模拟一下线路(回溯递归) 虽然对,但是超时,n越大时间越长,不可取,
#include <iostream>
using namespace std;
bool a[2][1001]={0};int length=0,n;long long int count=0;

void digui(int i,int j)
{
    if(length>=2*n-1){count++;
        count%=1000000007;
//        cout<<endl;
    }
    else
    {

    for(int k=-1;k<=1;k++)
     for (int l=-1;l<=1;l++)
     if(i+k>=0&&i+k<=1&&j+l<=n&&j+l>=1)
      {
      if (a[i+k][j+l]==1)
       {
         a[i+k][j+l]=0;
         length++;
//cout<<i+k<<" "<<j+l<<endl;
         digui(i+k,j+l);
         length--;
         a[i+k][j+l]=1;
       }
      }

    }
}
int main()
{
    //输入一个正整数
    cin>>n;
    for (int i=1;i<=n;i++)
       {
         a[0][i]=1;
         a[1][i]=1;
       }

   for (int i=0;i<2;i++ )
     for (int j=1;j<=n;j++)
{
       a[i][j]=0;
       digui(i,j);
       a[i][j]=1;

}
       cout<<count;
}

 

posted @ 2019-02-26 09:12  热忱a  阅读(169)  评论(0编辑  收藏  举报