一.题目描述
A,2,3,4,5,6,7,8,9 共9张纸牌排成一个正三角形(A按1计算)。要求每个边的和相等。
下图就是一种排法
A
9 6
4 8
3 7 5 2
这样的排法可能会有很多。
如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?
二.代码
public class test1{
static int arr[] = {1,2,3,4,5,6,7,8,9};
static int count = 0;
public static void main(String[] args){
f(0);
System.out.println(count/6);//镜面两种情况,旋转三种情况,重复了3*2=6,所以最后结果要除以6
}
public static void f(int n){
if(n==9){//结束递归
//判断是否三边加起来和一样
if(arr[0]+arr[1]+arr[2]+arr[3]==arr[3]+arr[4]+arr[5]+arr[6]&&arr[3]+arr[4]+arr[5]+arr[6]==arr[6]+arr[7]+arr[8]+arr[0]){
count++;
}
}
//全排列问题的解决模板:
for(int i=n;i<9;i++){
int t=arr[n];
arr[n]=arr[i];
arr[i]=t;
f(n+1);
t=arr[n];
arr[n]=arr[i];
arr[i]=t;
}
}
}
三.知识点
1.全排列问题分析:
把待全排列记录分为两个部分:
(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
递归的思想:给你部分记录,全排列就是所有可能出现在第一个位置的记录与剩下的元素的全排列,剩下的元素的全排列又是剩下的可能出现在第一个位置的元素与剩下的元素的全排列,依次重复下去….
完整代码如下:
f方法接收三个参数,数组arr,起始位置start,终止为止end,意思就是完成arr数组从start到end之间记录的全排列。
分两个步骤:
(1)确定第一位的字符
数组arr从start到end的所有记录都可以出现在第一个位置,所以直接一个for循环,考虑了这所有的情况。在for循环中,交换i和start位置的数,保证当前i指向的记录出现在第一个位置,也就是start指向的位置
(2)剩下的记录继续做全排列
这个就是一个递归函数的调用,只需要修改起始位置,也就是start+1,因为start的位置已经放了记录,所以只需要继续做从start+1到end的全排列即可
因此为了保证每一次的交换不会对下一次的交换产生影响,要重新交换一下位置,也就是复原,不然对下一次的交换就有影响了
递归的终止条件就是当start==end,也就是只有一个记录需要做全排列,也就是到了最后一个记录,这就是全排列的一种情况,输出本次的记录,也就是数组arr即可。
2.全排列问题代码:
public class test1{
static int arr[] = {1,2,3};
public static void main(String[] args){
f(arr,0,arr.length-1);//方法调用
}
public static void f(int []n,int start,int end){
if(start==end){//结束条件
for(int s:arr){//循环输出
System.out.print(s);
}
System.out.println();//隔一行
}
for(int i=start;i<arr.length;i++){//递归函数交换
int t=arr[start];
arr[start]=arr[i];
arr[i]=t;
f(arr,start+1,arr.length-1);
t=arr[start];//回溯
arr[start]=arr[i];
arr[i]=t;
}
}
}