题目描述
如图
有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)
比如
中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
解决方法
先选出组合再进行判断连通性
public class A_7 {
public static ArrayList<Integer> path = new ArrayList<>();
public static int num;
public static int[][] map = new int[3][4];
//选出组合(12选5),回溯法求组合
public static void f(int[] a,int startIndex,int n) {
if(path.size()==n) {//path为选出的结果集,对结果集进行判断,是否连通
test(path);
return;
}
for (int i = startIndex; i < a.length; i++) {
path.add(a[i]);
f(a,i+1,n);
path.remove(Integer.valueOf(a[i]));
}
}
private static void test(ArrayList<Integer> path) {
for (Integer i : path) {
map[(i-1)/4][(i-1)%4] = 1;//将组合还原成二维矩阵
}
int x = (path.get(0)-1)/4;
int y = (path.get(0)-1)%4;
dfs(x,y);//找到一个起始点通过深度优先搜索算法进行判断是否连通
if(sum(map)==0) {//当map的元素都为0说明是连通的
num++;
System.out.println(path);
}
else
init(map);
}
private static void init(int[][] m) {
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[i].length; j++) {
map[i][j] = 0;
}
}
}
private static int sum(int[][] m) {
int sum = 0;
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[i].length; j++) {
sum += map[i][j];
}
}
return sum;
}
private static void dfs(int x, int y) {
map[x][y] = 0;
if(x-1>=0&&map[x-1][y]!=0) dfs(x-1,y);//向上
if(x+1<=2&&map[x+1][y]!=0) dfs(x+1,y);//向下
if(y-1>=0&&map[x][y-1]!=0) dfs(x,y-1);//向左
if(y+1<=3&&map[x][y+1]!=0) dfs(x,y+1);//向右
}
public static void main(String[] args) {
int[] a = {1,2,3,4,5,6,7,8,9,10,11,12};
f(a,0,5);
System.out.println(num);
}
}