蓝桥杯 - 剪邮票 (java)

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

【图1.jpg】
【图2.jpg】

【图3.jpg】

 

注意 : 单纯使用 dfs 是不行的,因为 dfs 只能 剪出可以一笔画成的相连邮票,所以我们需要先枚举出所有 剪邮票的 方案,然后 判断 每一组是否 相连.

代码:

	//用来存放每一次剪下的五张邮票
	public static int[] tmp = new int[5];
	//存放原来的整张邮票
	public static int[][] stamp = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
	
	//记录每一组要剪下的 五张邮票的状态 (1号-12号)邮票
	public static boolean[] t = new boolean[13];	
	//每剪下一张,就用 w 数组记录当前 邮票 的状态(是否已剪)
	public static boolean[] w = new boolean[13];
	
	//统计剪的次数
	public static int depth = 0;
	//这是一个标记(每组邮票符合要求返回 true,反之返回 false)
	public static boolean label = false;
	
	public static void main(String[] args) {
		//统计方案次数
		int count = 0;
		//用枚举列举出 a b c d e 五张邮票的所有组合
		int a,b,c,d,e;
		for(a = 1; a <= 12 ;a++) {
			for(b = a+1; b <= 12 ;b++) {
				for(c = b+1; c <= 12 ;c++) {
					for(d = c+1; d <= 12 ;d++) {
						for(e = d+1; e <= 12 ;e++) {
							//将当前选中的邮票依次存放到 tmp 数组中
							tmp[0] = a;
							tmp[1] = b;
							tmp[2] = c;
							tmp[3] = d;
							tmp[4] = e;
							//在 t 数组中将 当前这五张邮票的状态锁定(置为true)
							changeStatusT();
							//检查这五张邮票是否能连接在一起
							if(check()) {
								//计数
								count++;
							}
							//对 t 数组进行初始化为 false,准备下一组邮票的检查
							initT();
						}
					}
				}
			}
		}
		System.out.println(count);
	}
	
	/**
	  * 锁定当前 五 张邮票的状态
	 */
	private static void changeStatusT() {
		for(int i = 0; i < 5; i++) {
			t[tmp[i]] = true;
		}
	}

	/**
	  * 将 t 数组置为初始状态.
	 */
	private static void initT() {
		for(int i = 0; i < 5; i++) {
			t[tmp[i]] = false;
		}
	}

	/**
	  * 初始化 w 数组(w:每剪一张,记录下邮票的状态)
	 */
	private static void initW() {
		for(int i = 0; i < 13;i++) {
			w[i] = false;
		}
	}

	/**
	  * 检查当前这组 邮票 是否相邻连接在一起
	 * @return
	 */
	private static boolean check() {
		//初始化一下标记
		label = false;  
		//初始化当前剪的次数
		depth = 0;
		//初始化 w 数组(置为false,表示所有的邮票都没被剪过)
		initW();
		
		//结束循环的条件
		boolean flg = false;
		for(int i = 0; i < 3; i++) {
			for(int j = 0; j < 4; j++) {
				//如果在 stamp 中找到第一张邮票,将下标传给 dfs,让它递归检测.
				if(stamp[i][j] == tmp[0]) {
					//在dfs中如果确定了满足要求,就会将 label 置为 true.
					dfs(i,j);
					flg = true;
					break;
				}
			}
			if(flg) break;
		}
		//返回判断结果
		return label;	
	}
	
	/**
	  * 从当前下标往四周开始剪邮票
	 * @param x  行
	 * @param y  列
	 */
	private static void dfs(int x, int y) {
		//递归结束条件,剪了五次,说明每张都被剪出来了
		if(depth == 5) {
			//标记为 满足要求
			label = true;
			return;
		}
		
		//判断当前剪的邮票是否在 当前这组邮票里,并且 还没有被剪过
		if(t[stamp[x][y]] == true && w[stamp[x][y]] == false) {
			//标记为 被剪了 状态
			w[stamp[x][y]] = true;
			//剪邮票的次数 +1
			depth++;
			//判断上面能不能剪
			if(x-1 >= 0) {
				dfs(x-1,y);
			}
			//下面能不能剪
			if(x+1 <= 2) {
				dfs(x+1,y);
			}
			//左边能不能剪
			if(y-1 >= 0) {
				dfs(x,y-1);
			}
			//右边能不能剪
			if(y+1 <= 3) {
				dfs(x,y+1);
			}
		}
	}

结果: 116

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值