一、问题描述
如【图1.jpg】, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。请你计算,一共有多少种不同的剪取方法。请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
二、题目类型:结果填空、全排列、DFS/BFS
三、解题思路及代码
首先,要给自己一个小小的肯定~耶,今天学习dfs、bfs可终于敲出来了(大佬轻喷,我的算法能力级别停留在幼儿园阶段),果然知识的引体很重要,《算法笔记》这本书真的很赞!
我的解法比其他博主写的方法要笨上许多,大家看看思路就行,嘿嘿。
思路:初始化 3*4 的二维数组和状态数组,对于这12个空,全排列出所有五个空的组合,在二维数字中把这五个空置为 1 ,并对此组合的进行bfs/dfs连通判断(用状态数组进行判断),把所有可以连通的组合加起来就是答案。
1 import java.util.ArrayDeque; 2 import java.util.Scanner; 3 4 public class CutTheStamps { 5 static int n;// n行 6 static int m;// m列 7 static int[][] arr;// 邻接矩阵 8 static boolean zt[][];// 状态数组 9 static int[] X = new int[] { 1, -1, 0, 0 };// 增量数组 10 static int[] Y = new int[] { 0, 0, 1, -1 }; 11 12 public static void main(String[] args) { 13 Scanner input = new Scanner(System.in); 14 n = input.nextInt(); 15 m = input.nextInt(); 16 arr = new int[n][m];// 默认0 17 zt = new boolean[n][m];// 默认false 18 int sum = 0;// 统计符合题目条件的剪法 19 // 全排列 20 for (int a = 0; a < 12; a++) { 21 for (int b = a + 1; b < 12; b++) { 22 for (int c = b + 1; c < 12; c++) { 23 for (int d = c + 1; d < 12; d++) { 24 for (int e = d + 1; e < 12; e++) { 25 arr[a / 4][a % 4] = 1; 26 arr[b / 4][b % 4] = 1; 27 arr[c / 4][c % 4] = 1; 28 arr[d / 4][d % 4] = 1; 29 arr[e / 4][e % 4] = 1; 30 bfs(a / 4, a % 4);// 从a开始搜索 31 int count = counts(zt);// 计算此组合剪法,邮票的连通数 32 if (count == 5) {// 等于5说明5张邮票都连通 33 sum++; 34 } 35 zt = new boolean[n][m];// 重置,准备下一个组合的判断 36 arr = new int[n][m];// 重置,准备下一个组合的判断 37 } 38 } 39 } 40 } 41 } 42 System.out.println(sum); 43 } 44 45 // 判断bfs后的状态数组中有多少个true 46 public static int counts(boolean[][] zt) { 47 int count = 0; 48 for (int i = 0; i < n; i++) { 49 for (int j = 0; j < m; j++) { 50 if (zt[i][j]) { 51 count++; 52 } 53 } 54 } 55 return count; 56 } 57 58 // 判断当前位置是否可以连通(入队列) 59 public static boolean judge(int x, int y) { 60 if (x >= n || x < 0 || y >= m || y < 0) 61 return false; 62 if (arr[x][y] == 0 || zt[x][y]) 63 return false; 64 return true; 65 } 66 67 public static void bfs(int x, int y) { 68 ArrayDeque<Node> queue = new ArrayDeque<Node>(); 69 Node node = new Node(x, y); 70 queue.add(node);// 入队 71 zt[x][y] = true;// 状态设置为已访问 72 while (!queue.isEmpty()) { 73 Node top = queue.poll();// 取出队头元素 74 for (int i = 0; i < 4; i++) {// 判断上、下、左、右四个位置是否可以入队 75 int newX = top.x + X[i]; 76 int newY = top.y + Y[i]; 77 if (judge(newX, newY)) { 78 Node n = new Node(newX, newY); 79 queue.add(n);// 入队 80 zt[newX][newY] = true;// 状态设置为已访问 81 } 82 } 83 } 84 } 85 } 86 87 class Node { 88 int x; 89 int y; 90 91 public Node(int x, int y) { 92 this.x = x; 93 this.y = y; 94 } 95 }
四、反思与总结
这类题目我觉得有点绕,要多练习、多思考。冲鸭~