最近看蓝桥杯的题目,有好多这种数学基本方式的题目,有些题目如果可以总结出公式或者是递推公式,就会很容易就能算出结果。这种全排列的题目,如果只是填空的话,不做提前判断减少分支的话,暴力破解等个一两分钟也能算出来。要是编程的话就需要更多的判断来减少时间开销了。
全排列的基本思想是:
把待全排列记录分为两个部分:
(1) 确定第一位一个记录
(2) 剩下的所有元素
所有记录的全排列就是所有可能出现在第一个位置的记录与剩下所有元素的全排列。
以[1,2,3]为例,
1,2,3的全排列可以看作是
1,[2,3的全排列]
[2,3]的全排列又可以看作是
2,[3的全排列]—————对应123
3,[2的全排列]—————对应132
2,[1,3的全排列]
[1,3]的全排列又可以看作是
1,[3的全排列]—————对应213
3,[1的全排列]—————对应231
3,[1,2的全排列]
[1,2]的全排列又可以看作是
1,[2的全排列]—————对应312
2,[1的全排列]—————对应321
所以很明显,这就是一个递归的思想:给你部分记录,全排列就是所有可能出现在第一个位置的记录与剩下的元素的全排列,剩下的元素的全排列又是剩下的可能出现在第一个位置的元素与剩下的元素的全排列,依次重复下去….
分两个步骤:
- 确定第一位的字符
数组arr从start到end的所有记录都可以出现在第一个位置,所以直接一个for循环,考虑了这所有的情况。在for循环中,swap方法就是交换i和start位置的数,保证当前i指向的记录出现在第一个位置,也就是start指向的位置 - 剩下的记录继续做全排列
这个就是一个递归函数的调用,只需要修改起始位置,也就是start+1,因为start的位置已经放了记录,所以只需要继续做从start+1到end的全排列即可
下面以蓝桥杯的题目说一下全排列的实现
题目寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ – □ = □
□ × □ = □
□ ÷ □ = □
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 – 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 – 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
代码实现
package LanQiao;
public class 寒假作业 {
static int count = 0;
public static void main(String[] args) {
int[] a = {1,2,3,4,5,6,7,8,9,10,11,12,13};
dfs(a,0,12);
System.out.println(count);
}
//递归实现全排列
public static void dfs(int[] a, int start, int end) {
if (start == end) {
if (judge(a))
count++;
return;// 一次全排列
}
for (int i = start;i<=end;i++) {
swap(a, i, start);
dfs(a, start+1, end);
swap(a, i, start);//因为修改是对唯一的数组做了修改,为了不影响后续的排列,
//每一次会递归完成并回到这里时都要将交换复原
}
}
//交换两个数组值的位置
public static void swap(int a[],int i,int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//判断是否符合
public static boolean judge(int a[]) {
if (a[1] + a[2] == a[3] && a[4] - a[5] == a[6] && a[7] * a[8] == a[9]
&& (a[10] / a[11] == a[12] && a[10] % a[11] == 0)) {// 必须判断余数为零
return true;
} else {
return false;
}
}
}
等待一段时间输出的结果是64