![](https://i-blog.csdnimg.cn/blog_migrate/4b9456b25b4159fd078c16b07768872e.png)
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
【解题思路】
这题使用动态规划,状态转移方程比较复杂,找到了状态转移方程这题就轻松多了。
状态转移方程: b[i] = 2*b[i]
a[i] = 2*a[i-1] + b[i] + 2*2*a[i-2]
sum = 4*a[n] sum = sum + 2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])
解释一下状态转移方程,这道题目分两种情况,一种是4个顶点出发另一种就是从中间出发,假设一共有2*n个格子:
1、4个顶点出发,以一个顶点作为例子讲解
情况①,第一步走同一列的另一个格子,如图A→B,B就可以到C或者D,这种情况可以转换成a[i-1]
2*a[i-1]
情况②,第一步走另一列最后回到同一列的另一个格子,如图A→C或者A→D,最后回到B,这种情况用数组b存储可以转化成b[i-1]
b[i] = 2*b[i-1]
情况③,第一步走另一列再到同一列的另一个格子再到另一列,如图A→C→B→D或者A→D→B→C,C又可以到E或者F,D也可以到E或者F,这种情况就转换成a[i-2]
2*2*a[i-2]
a[i] = 2*a[i-1] + b[i] + 2*2*a[i-2]
所以4个顶点出发的方案数有 sum = 4 * a[n]
2、从中间开始经过同一列的另一个格子后到结尾,以i=3的E为例子讲解
以i开始分割,左边ABCDEF可以看做以E为顶点的一组格子最后回到同一列的F,右边可以看做以G或者以H为顶点的一组格子,这样就有b[i]*a[n-i]*2种方案;同理右边EFGHIJ看做以E为顶点最后回到同一列F的一组格子,左边ABCD可以看做以C或者D为顶点的的一组格子,这样就有b[n-i+1]*a[i-1]*2种方案
同理也可以F为开始的地方,那么从第i列开始刷漆的方法就有 2*(b[i]*a[n-i]*2 + b[n-i+1]*a[i-1]*2)中方案,也就是2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])种方案
所以最终sum = sum + 2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])
#include<iostream>
using namespace std;
const int Maxnum = 1000000007;
int main()
{
//__int64是因为VC++6.0不支持long long , 蓝桥杯的时候可以改成long long
__int64 a[1001]; //用于求顶点开始的方法数
__int64 b[1001]; //用于求顶点开始回到同一列的方法数
int sum; //cout不支持__int64就改成int了
int n,i;
cin>>n;
b[1] = 1;
b[2] = 2;
a[1] = 1;
a[2] = 6; //三种情况2+2+2
for(i=3;i<=n;i++)
{
b[i] = (2*b[i-1])%Maxnum; //边操作边取余
a[i] = (2*a[i-1]+b[i]+2*2*a[i-2])%Maxnum;
}
sum = 4*a[n]; //4个顶点
for(i=2;i<n;i++) //求中间开始的方法数
sum = (sum+2*2*(b[i]*a[n-i]+b[n-i+1]*a[i-1]))%Maxnum;
cout<<sum<<endl;
return 0;
}