试题 历届试题 格子刷油漆

  【资源限制】  时间限制:1.0s   内存限制:256.0MB 问题描述   X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。

格子刷油漆 算法 第1张
  你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
  比如:a d b c e f 就是合格的刷漆顺序。
  c e f d a b 是另一种合适的方案。
  当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。 输入格式   输入数据为一个正整数(不大于1000) 输出格式   输出数据为一个正整数。 样例输入 2 样例输出 24 样例输入 3 样例输出 96 样例输入 22 样例输出 359635897   解题思路   在矩形的长度大于2的时候有两种情况:      1.从两边上的四个格子开始出发       2.从中间开始出发   首先分析第一种情况(从两边上的四个格子开始出发)     由于四个格子都在最边上,没有差别,因此分析一个格子的所有情况乘以4即可得到从边上出发的情况总和。     从最边上走有三种走法:(方式是我胡写的)       ①不回头式,把本列都走过再走下一列       格子刷油漆 算法 第2张

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

         比如此图,从A开始出发,先走B,再走下一列,走到第二列的路线有两种,在i等于1的时候只有A到B一种走法,当i等于2的时候,i有1*2种走法,i等于3的时候有1*2*2种走法

         由此推出当在第i列的时候有a[i] = 2*a[i-1];

             ②返回式  每次先走下一列,最后返回到开头相对的格子             格子刷油漆 算法 第3张 格子刷油漆 算法 第4张

        比如上两个图 从A点出发先到达C点或者D点 所以有b[i] = 2*b[i-1]  (由于此方式能返回到开始格子的对面,所以单独作为一种方式存储,在后面能用到)

        ③一步一回头式 先走下一列,再返回上一列,再返回下一列的对面,然后再访问下一列 (&&*……&*%……&)

       格子刷油漆 算法 第5张格子刷油漆 算法 第6张

         类似于上图这样子两种方式,然后到达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代表列数

   第二种情况(从中间格子开始出发) :此情况必须应用在N大于2的时候     当从中间走的时候就将矩形分成了两部分,有先从左走和先从右走的区别(排列方式不一样)。          无论先从左走还是先从右走,先走的那一个方向必须能返回到当前格子的相对的格子,如果不能就返回不了了     这种方法我在上面提过,就是存储为b[i]的数组     从左边先走有两种方式(比如从A走)A -> C 和  A -> D两种     格子刷油漆 算法 第7张格子刷油漆 算法 第8张

      从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])

       

      所以最终结果是sum1+sum2 = 4*a[n]+  4*(b[i]*a[i-1]+b[n-i]*a[i-1])    由于格子刷油漆 算法 第9张

 

     需要用到 a[i-2] 的结果 所以要给a[1]和a[2]赋值 从a[3]开始算,求a[3] 的时候需要求得b[2],所以要给出a[1]、a[2]、b[1]、b[2]

   当n等于1的时候 a[1] = 1 , b[1] = 1  (实际为0,因为只有1列,没法算,这里改为1,是便于理解,实际没影响)

   当n等于2的时候,只有从四个点开始的情况,所以罗列出来 a[2] = 6 , b[2] = 2;

 

   格子刷油漆 算法 第10张格子刷油漆 算法 第11张

   格子刷油漆 算法 第12张     格子刷油漆 算法 第13张

     格子刷油漆 算法 第14张格子刷油漆 算法 第15张

 

 

 把思路转换为代码:

 

 

import java.util.Scanner;

public class 格子刷油漆 {
	public static void main(String[] args) {
		int Mod = 1000000007;
		long[] a = new long[1001];
		long[] b = new long[1001];
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();//列数
		a[1] = 1;
		b[1] = 1;
		a[2] = 6;
		b[2] = 2;
		if (N==1) {
			System.out.println("2");
		}
		if (N==2) {
			System.out.println(a[2]*4);
		}
		for (int i = 3; i <=N; i++) {//从头出发
			a[i] = (2*a[i-1]+2*b[i-1]+4*a[i-2])%Mod;
			b[i] = (2*b[i-1])%Mod;
		}
		long sum = 4*a[N]%Mod;
		for (int i = 2; i < N; i++) {//从中间出发,在2到N-1之间
			sum+=4*(b[i]*a[N-i]%Mod+b[N-i+1]*a[i-1]%Mod)%Mod;
			sum%=Mod;
		}
		System.out.println(sum);
	}
}

  

 

 思路借鉴CSDN博主 酱懵静  https://blog.csdn.net/the_ZED/article/details/104724184

 

 

 

 

   

     

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄