题目描述
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
这题还是有一定难度的,解决此类问题,一般涉及到数学坐标分析的功底,乍一看我们能想到使用深搜,搜出5个满足连通的方格,存入Set集合自动判重,注意set里面存的不能为数组,只能是一个包装类或者集合,这里我们使用map去存5个方格,再放入set中
1.判断连通的条件
- 从第一个方格开始,每一个方格必须与前几个方格中的一个相邻
(局部连通构造全局连通,有点像动态规划) - 相邻的条件判断:数值相差为4,或数值相差为1(且两数必须在同一行)
代码
package competion2016;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
public class 方格填数2 {
static int arr[]=new int[5];
static int ants=0;
static Set<HashSet<Integer>> set=new HashSet<HashSet<Integer>>();
static int visit[]=new int[13];
public static void dfs(int x) {
// TODO 自动生成的方法存根
if(x==5) {//五个数找到了
HashSet<Integer> hashSet=new HashSet<Integer>();
for (int i = 0; i < 5; i++) {
hashSet.add(arr[i]);
}
set.add(hashSet);
return;
}
for (int i = 1; i <= 12; i++) {
if (visit[i]==0&&check(x,i)) {
visit[i]=1;
arr[x]=i;
dfs(x+1);
visit[i]=0;
}
}
}
//判断前a[0],到a[x-1]中是否有元素和i相临,递归的分析
public static boolean check(int x,int i) {
if(x==0) {
return true;
}
for (int k = 0; k < x; k++) {
if(adjust(arr[k], i)) {
return true;
}
}
return false;
}
//判断两个数相邻
public static boolean adjust(int x,int y) {
int mid=Math.min(x,y);
int max=Math.max(x,y);
x=mid;
y=max;
if(y-x==4||(y-x==1&&x%4!=0)) {
return true;
}
return false;
}
//深搜,且判断某点是否与前面的其中一个点相邻
public static void main(String[] args) {
// TODO 自动生成的方法存根
dfs(0);
System.out.println(set.size());
}
}