华为OD机试-九宫格
题目描述
九宫格是一款广为流传的游戏,起源于河图洛书。
游戏规则是:1到9九个数字放在3×3的格子中,要求每行、每列以及两个对角线上的三数之和都等于15.
在金麻名著《射雕英雄传》中黃蓉曾给九宫格的一种解法,口诀:戴九恩一,左三右七,二四有肩,八六为足,五居中央。解法如图所示。
现在有一种新的玩法,给九个不同的数字,将这九个数字放在3×3的格子中,要求每行、每列以及两个对角线上的三数之积相等(三阶积幻方)。其中一个三阶幻方如图:
解释:每行、每列以及两个对角线上的三数之积相等,都为216。请设计一种算法,将给定的九个数宇重新排列后,使其满足三阶积幻方的要求。
排列后的九个数宇中:第1-3个数字为方格的第一行,第4-6个数宇为方格的第二行,第7-9个数字为方格的第三行。
输入描述
九个不同的数宇,每个数字之间用空格分开。
0<数字<10^7。0<排列后满足要求的每行、每列以及两个对角线上的三数之积 < 2^31-1。
输出描述
九个数字所有满足要求的排列,每个数字之间用空格分开。每行输出一个满足要求的排列。
要求输出的排列升序排序,即:对于排列A (A1.A2.A3…A9)和排列B(B1,B2,B3…B9),从排列的第1个数字开始,遇到Ai<Bi,则排列A<排列B (1<=j<=9)。
说明:用例保证至少有一种排列组合满足条件。
用例
输入
75 36 10 4 30 225 90 25 12
输出
10 36 75 225 30 4 12 25 90
10 225 12 36 30 25 75 4 90
12 25 90 225 30 4 10 36 75
12 225 10 25 30 36 90 4 75
75 4 90 36 30 25 10 225 12
75 36 10 4 30 225 90 25 12
90 4 75 25 30 36 12 225 10
90 25 12 4 30 225 75 36 10
题目解析
简单的全排列问题。
关于全排列的入门,可以看
组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列_哔哩哔哩_bilibili
练习题可以做leetcode上:LeetCode - 46 全排列
基于回溯算法的全排列求解是一种暴力解法,即枚举出全部排列情况,因此对大数量级而言,我们应该慎用,但是本题,已经明确指出了求解9个数字的全排列,因此排列情况共有9!个,即362880个,数量级还好,因此可以使用暴力求解。
另外,求出符合要求的排列,还需要对各排列进行排序,排序是按各个数字大小来比较的,大家可以看下代码中关于排序的实现。
JavaScript算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.on("line", (line) => { const arr = line.split(" ").map(Number); getResult(arr); }); function getResult(arr) { const res = []; dfs(arr, [], [], res); res.sort((a, b) => { for (let i = 0; i < 9; i++) { if (a[i] !== b[i]) return a[i] - b[i]; } return 0; }); res.forEach((a) => console.log(a.join(" "))); } function dfs(arr, used, path, res) { if (path.length === arr.length) { if (check(path)) { res.push([...path]); } return; } for (let i = 0; i < arr.length; i++) { if (!used[i]) { path.push(arr[i]); used[i] = true; dfs(arr, used, path, res); used[i] = false; path.pop(); } } } function check(a) { /** * a0 a1 a2 * a3 a4 a5 * a6 a7 a8 */ const r1 = a[0] * a[1] * a[2]; const r2 = a[3] * a[4] * a[5]; if (r1 != r2) return false; const r3 = a[6] * a[7] * a[8]; if (r1 != r3) return false; const c1 = a[0] * a[3] * a[6]; if (r1 != c1) return false; const c2 = a[1] * a[4] * a[7]; if (r1 != c2) return false; const c3 = a[2] * a[5] * a[8]; if (r1 != c3) return false; const s1 = a[0] * a[4] * a[8]; if (r1 != s1) return false; const s2 = a[2] * a[4] * a[6]; if (r1 != s2) return false; return true; }
Java算法源码
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); Integer[] arr = Arrays.stream(sc.nextLine().split(" ")).map(Integer::parseInt).toArray(Integer[]::new); getResult(arr); } public static void getResult(Integer[] arr) { boolean[] used = new boolean[arr.length]; LinkedList<Integer> path = new LinkedList<>(); ArrayList<Integer[]> res = new ArrayList<>(); dfs(arr, used, path, res); res.sort( (a, b) -> { for (int i = 0; i < 9; i++) { if (!Objects.equals(a[i], b[i])) return a[i] - b[i]; } return 0; }); for (Integer[] re : res) { StringJoiner sj = new StringJoiner(" "); for (Integer i : re) { sj.add(i + ""); } System.out.println(sj); } } public static void dfs( Integer[] arr, boolean[] used, LinkedList<Integer> path, ArrayList<Integer[]> res) { if (path.size() == arr.length) { if (check(path)) { Integer[] a = path.toArray(new Integer[0]); res.add(a); } return; } for (int i = 0; i < arr.length; i++) { if (!used[i]) { path.add(arr[i]); used[i] = true; dfs(arr, used, path, res); used[i] = false; path.removeLast(); } } } public static boolean check(LinkedList<Integer> path) { Integer[] a = path.toArray(new Integer[0]); int r1 = a[0] * a[1] * a[2]; int r2 = a[3] * a[4] * a[5]; if (r1 != r2) return false; int r3 = a[6] * a[7] * a[8]; if (r1 != r3) return false; int c1 = a[0] * a[3] * a[6]; if (r1 != c1) return false; int c2 = a[1] * a[4] * a[7]; if (r1 != c2) return false; int c3 = a[2] * a[5] * a[8]; if (r1 != c3) return false; int s1 = a[0] * a[4] * a[8]; if (r1 != s1) return false; int s2 = a[2] * a[4] * a[6]; if (r1 != s2) return false; return true; } }
Python算法源码
# 输入获取 arr = list(map(int, input().split())) # 算法入口 def getResult(arr): res = [] dfs(arr, [False for i in range(len(arr))], [], res) res.sort(key=lambda x: (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8])) for a in res: print(" ".join(map(str, a))) # 全排列求解 def dfs(arr, used, path, res): if len(path) == len(arr): if check(path): res.append(path[:]) return for i in range(len(arr)): if not used[i]: path.append(arr[i]) used[i] = True dfs(arr, used, path, res) used[i] = False path.pop() # 检查排列a是否符合 每行、每列、两个对角线的乘积相同 def check(a): r1 = a[0] * a[1] * a[2] r2 = a[3] * a[4] * a[5] if r1 != r2: return False r3 = a[6] * a[7] * a[8] if r1 != r3: return False c1 = a[0] * a[3] * a[6] if r1 != c1: return False c2 = a[1] * a[4] * a[7] if r1 != c2: return False c3 = a[2] * a[5] * a[8] if r1 != c3: return False s1 = a[0] * a[4] * a[8] if r1 != s1: return False s2 = a[2] * a[4] * a[6] if r1 != s2: return False return True # 调用算法 getResult(arr)