Java实现蓝桥杯历届试题格子刷油漆

问题描述
  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

问题分析:

首先,对这些墙刷油漆主要分为两大类:

1.从最边缘的四个格子出发,然后遍历完所有格子;

2:从中间的某个格子出发,先遍历完一边的格子,回到这个格子所对的格子,然后遍历另一边的格子。

所以,我们不妨用两个数组来表示这两种情况:

1.a[i]数组表示从最边缘的四个格子中某个出发,遍历完长度为i,个数为2i个格子的所有种类数;

2.b[i]数组表示从除了最边缘的四个格子外的某个中间的格子出发,遍历完一边回到所对的格子;

然后,我们来分别分析a[i]和b[i]两种不同的情况:

1.a[i]第一种情况:先走这个格子(以左上角的格子为例)所对的下面的格子,然后从下面这个格子的位置出发,有两种走法,分别到第二列的两个格子,所以第一种情况有:

2a[i-1]种;a[i]第二种情况:(举例)先从左上角的格子走到第二列某个格子,然后从第二列的格子出发,遍历完右面所有的格子,再回到第二列格子所对的格子,最后到第一列未遍历的格子,所以这种情况就是我们定义的b[i];a[i]第三种情况:就是遍历完一二列的所有格子,从第三列的格子出发,进行遍历。由于遍历完一二列的所有格子有四种情况,所以第三种情况为:4a[i-2];

所以,a[i]=2a[i-1]+b[i]+4a[i-2];

2.b[i]的情况:b[i]比较简单,只有两种情况,从同一行的格子出发,回到他所对的格子;或者从他对角的格子出发,回到他所对的格子。

所以,b[i]=2*b[i-1];

接下来,就是算总和:

1.四个角:定义sun=4*a[n];

2.设从第i列开始,则前面有i-1列,后面有n-i列。

第i列有两个格子,这两个格子所表示的情况数是相同的,所以只需要讨论一个。

然后,我们以第i列的上面的格子为例,先遍历他的左边,然后遍历右边。(回到他所对的格子,遍历右边时,又分为两种情况。从第i+1列上面的格子开始和从下面的格子开始)

即b[i]2a[n-i],化简得:2*b[i-1]2a[n-i];

同理得:先遍历右边,再遍历左边为:2*b[n-i]2a[i-1];

然后又因为a[1]=1;a[2]=6;b[1]=1;

import java.util.Scanner;


public class 格子刷油漆 {
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		long a[]=new long[n+1];
		long b[]=new long[n+1];
		long sum;
		b[1]=1;
		for(int i=2;i<=n;i++){
			b[i]=2*b[i-1]%1000000007;
		}
		a[1]=1;a[2]=6;
		for(int i=3;i<=n;i++){
			a[i]=(2*a[i-1]+b[i]+4*a[i-2])%1000000007;
		}
		sum=(4*a[n])%1000000007;
		for(int i=2;i<n;i++){
			sum+=((8*b[i-1]*a[n-i])%1000000007+(8*b[n-i]*a[i-1])%1000000007)%1000000007;//必须每个项都取余,防止有大于这个数的情况
			sum%=1000000007;
		}
		System.out.println(sum);
	}


}

到处转载只是为了给复习的人提供便利,看一个博主就能找到挺全的题和题解
转自:https://blog.csdn.net/qq_22891105/article/details/51050565

原文地址:https://www.cnblogs.com/a1439775520/p/13079005.html