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;
}
}