试题 历届试题 格子刷油漆
问题描述
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
解题思路
首先分析第一种情况(从两边上的四个格子开始出发):
①不回头式
把本列都走过再走下一列
比如此图,从A开始出发,先走B,再走下一列,走到第二列的路线有两种,在i等于1的时候只有A到B一种走法,当i等于2的时候,i有1*2种走法,i等于3的时候有1*2*2种走法
由此推出当在第i列的时候有a[i] = 2*a[i-1];
②返回式
每次先走下一列,最后返回到开头相对的格子
比如上两个图 从A点出发先到达C点或者D点 所以有b[i] = 2*b[i-1] (由于此方式能返回到开始格子的对面,所以单独作为一种方式存储,在后面能用到)
③一步一回头式
先走下一列,再返回上一列,再返回下一列的对面,然后再访问下一列
类似于上图这样子两种方式,然后到达E , F 自然有两种方式,所以推出 a[i] = 2*2*a[i-2]
所以第一种情况得出结论:a[i] = 2*a[i-1]+2*b[i-1]+4*a[i-2]
开头说过分析一个点,所以把四个点的都加起来就是 sum1 = 4*a[n] //n代表列数
第二种情况(从中间格子开始出发):
从A出发,最终到达B ,上面已经分析过 , 有b[i]种方法
然后分析从E或者F走,从E或F走可以回头式的走,也可以一步走到头,跟从最边上点开始走的方式相同,此处避免冗余不再举例,不懂得可以再翻到头看,所以有a[n-i]种方法。
在第i列也可以从B走,与A走情况相同,结果乘以2即可,从B到E和F有两种方法,所以结果也要乘以2
因此总的走法有 2*2*(b[i]*a[i-1])
从右先走,与从左走是相颠倒的
从A往右走,最终返回B,有b[n-i+1]种方法,也可以从B出发,最终返回A,最终结果要乘以2
从B往左走有两种方法,到达D或C,所以结果也要乘以2
从E或F向左走,有a[i-1]种方法
所以从右先走右有2*2*(b[n-i]*a[i-1])种走法
从左先走与从右先走加起来就是sum2 = 4*(b[i]*a[i-1]+b[n-i]*a[i-1])
a[i-2] 的结果 所以要给a[1]和a[2]赋值 从a[3]开始算,求a[3] 的时候需要求得b[2],所以要给出a[1]、a[2]、b[1]、b[2]
当n a[1] = 1 , b[1] = 1 (实际为0,因为只有1列,没法算,这里改为1,是便于理解,实际没影响)
当n等于2的时候,只有从四个点开始的情况,所以罗列出来 a[2] = 6 , b[2] = 2;
代码:
1 import java.util.Scanner; 2 3 public class 格子刷油漆 { 4 public static void main(String[] args) { 5 int Mod = 1000000007; 6 long[] a = new long[1001]; 7 long[] b = new long[1001]; 8 Scanner scanner = new Scanner(System.in); 9 int N = scanner.nextInt();//列数 10 a[1] = 1; 11 b[1] = 1; 12 a[2] = 6; 13 b[2] = 2; 14 if (N==1) { 15 System.out.println("2"); 16 } 17 if (N==2) { 18 System.out.println(a[2]*4); 19 } 20 for (int i = 3; i <=N; i++) {//从头出发 21 a[i] = (2*a[i-1]+2*b[i-1]+4*a[i-2])%Mod; 22 b[i] = (2*b[i-1])%Mod; 23 } 24 long sum = 4*a[N]%Mod; 25 for (int i = 2; i < N; i++) {//从中间出发,在2到N-1之间 26 sum+=4*(b[i]*a[N-i]%Mod+b[N-i+1]*a[i-1]%Mod)%Mod; 27 sum%=Mod; 28 } 29 System.out.println(sum); 30 } 31 }
致谢
思路借鉴CSDN博主 酱懵静 https://blog.csdn.net/the_ZED/article/details/104724184