2016年第七届蓝桥杯(javaB组)--------剪邮票

7 篇文章 0 订阅
7 篇文章 0 订阅

7.剪邮票

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

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

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

按顺序的图1-3

花了几个小时,主要是自己写的思路一开始有bug,看了别人博客大多数是暴力加上联通块,自己写了一个全排加set去重

 

首先,全排就不用说了,全排后就是剪枝了,上下差4,左右差1,但是注意 4与5  8与9 不计算,我用的是一维数组所以写起来麻烦了一些这也是我时间花费的问题,如果写二维联通用bfs去实现不用那么久,那一维数组怎么去检测是否联通,经过测试,每个格子的相邻格子数的总和大于等于8就为联通,这个我是发现有3个格子和2个格子分开的情况后发现的,可以试着计算一下,5个格子要联通必定大于等8.

 

最后,联通计算完了,还差一部,全排的话会有一个问题就是会有重复,比如1,2,3,4,5格联通,  5,4,3,2,1联通 ,但是他们是同样的格子,不注意的话就会错过了,那么解决重复,我是利用了set特性,把全排剪枝好的数组先排序Arrays.sort,排序后肯定是从小到大,随后加入set后输出set.size,就可以得到结果了。

结果为:116

说实话这道题目有点麻烦,考虑的点有点多,像暴力加联通也确实可以,下面附上代码,写得有点乱没有整理,懒得去弄了记录一个思路。。。。。

package p2017_7;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Main {
	static int num[]= {0,0,0,0,0,0,0,0,0,0,0,0};
	static int targetnum[]= {0,0,0,0,0};
	static int sum=0;
	static int numsum=0;
	static Set<String> set=new HashSet<String>();
	public static void main(String[] args) {
		dfs(0);
		System.out.println(set.size());
	}
	//全排
	static void dfs(int step) {
		if (step==5) {	
			if (targetloop()==true) {
				String midnumString="";
				int midnums[]=new int[5];
				for (int i = 0; i < targetnum.length; i++) {
					midnums[i]=targetnum[i];
				}
				//排序去重
				Arrays.sort(midnums);
//				for (int i = 0; i < midnums.length; i++) {
//					System.out.print(midnums[i]+" ");
//				}
				for (int i = 0; i < midnums.length; i++) {
					midnumString+=midnums[i];
				}
				//利用set特性去重
				set.add(midnumString);
				System.out.print(" 联通共:"+numsum+"次");
				System.out.println();
			}
			return;
		}
		for (int i = 0; i < num.length; i++) {
			if (num[i]==0) {
				targetnum[step]=i+1;
				num[i]=1;
				dfs(step+1);
				num[i]=0;
			}
		}
	}
	//剪枝(上下差4,左右差1,4,5,8,9不算入,计算联通大于8的都是连在一起的)
	static boolean targetloop() {
		numsum=0;
		for (int i = 0; i < targetnum.length; i++) {
			int targetyes=0;
			//循环计算每个格子的有几个相邻(所有格子联通大于8就是符合)
				for (int j =0; j < targetnum.length; j++) {
					if(i!=j&&(Math.abs(targetnum[i]-targetnum[j])==1||Math.abs(targetnum[i]-targetnum[j])==4)) {
						if ((targetnum[i]==4&&targetnum[j]==5)||(targetnum[i]==8&&targetnum[j]==9)||(targetnum[i]==5&&targetnum[j]==4)||(targetnum[i]==9&&targetnum[j]==8)) {
							continue;
						}
						targetyes=1;
						numsum++;
					}
				}
				if (targetyes==0) {
					return false;
				}
			}
		if (numsum<8) {
			return false;
		}
		return true;
	}
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值