如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
解题思路: 1:在12个数中找5个数的全排列 ,使用一维数组进行全排列; 2:一维数组转二维数组进行筛选; 3:每个全排列结果的二维数组中元素,都是由许多1构成,只看所有的1是否全部连通,二维数组连通性的检查,是二维数组操作非常经典的算法,输出结果。
public class Demo_7_08 {
static int[] arr=new int[] {0,0,0,0,0,0,0,1,1,1,1,1};
static boolean[] boo=new boolean[12];
static int ans;
public static void main(String[] args) {
int[] help=new int[12];
//12中选5个只要标记5个1,全排列就可以求出所有组合情况
f(help,0);
System.out.println(ans);
}
public static void f(int[] help,int k) {
if(k==12) {
if(check(help)){
ans++;
}
return;
}
for(int i=0;i<12;i++) {
//如果第一个数和第二个数相等,选第一个,不选第二个和选第二个不选第一个是相同情况,跳过
if(i>0&&arr[i]==arr[i-1]&&!boo[i-1]) continue;
if(!boo[i]) {
boo[i]=true; //选了就标记处理过
help[k]=arr[i]; //选中它放到help数组中
f(help,k+1);
boo[i]=false; //回溯
}
}
}
public static boolean check(int[] help) {
int[][] keep=new int[3][4];
//将一维数组转二维数组
for(int i=0;i<3;i++) {
for(int j=0;j<4;j++) {
if(help[i*4+j]==1) {
keep[i][j]=1;
}else
keep[i][j]=0;
}
}
int count=0; //统计有多少个块
for(int i=0;i<3;i++) {
for(int j=0;j<4;j++) {
if(keep[i][j]==1) {
dfs(keep,i,j);
count++;
}
}
}
return count==1;
}
public static void dfs(int[][] keep,int x,int y) {
keep[x][y]=0; //找到一个1标记为0,防止无限递归,类似于消除水洼问题
//分别查看四个方向的连通性
if(x-1>=0&&keep[x-1][y]==1) dfs(keep,x-1,y);
if(x+1<=2&&keep[x+1][y]==1) dfs(keep,x+1,y);
if(y-1>=0&&keep[x][y-1]==1) dfs(keep,x,y-1);
if(y+1<=3&&keep[x][y+1]==1) dfs(keep,x,y+1);
}
}
输出:116