JAVA全排列!!!

在各类比赛中,运用到全排列的方法的题有很多,有很多完成全排列的方法。例如:下面介绍两种运用递归实现的全排列,并通过蓝桥杯试题进行验证。

一、方法一:利用递归,逐渐将后面的数字互换位置,进而实现全排列。因为递归本身就不是很好理解所以下面给出实现的代码,通过代入数据可以加快理解,其中形参数组a存储了1-9个数字,n的值为0:

 

public static void fun(int a[], int n) {
		if (n == 9) {
			//此时的数组a已经完成了一种全排列
		} else
			for (int i = n; i < 9; i++) {
				{
					int temp = a[i];
					a[i] = a[n];
					a[n] = temp;
				}
				fun(a, n + 1);

				{
					int tamp = a[i];
					a[i] = a[n];
					a[n] = tamp;
				}
			}
	}

 

因为这种方法没有涉及到大小值得比较,所以对于不同的字符进行全排列仍然可以实现:

 

public static void fun(char a[], int n) {
			if (n == 9) {
				//此时已经完成其中的一种全排列
			} else
				for (int i = n; i < 9; i++) {
					{
						char temp = a[i];
						a[i] = a[n];
						a[n] = temp;
					}
					fun(a, n + 1);

					{
						char tamp = a[i];
						a[i] = a[n];
						a[n] = tamp;
					}
				}
		}

 

 

二、方法二:仍然使用递归进行实习,与上一种方法比较类似,只是在初始方面没有对数组进行赋值,而是再循环中进行实现:

 

 

private static void dfs(int[] a, boolean[] visit, int num) {  
        if (num==11) {  
            //此时完成其中一种全排列
        }  
        for (a[num] = 0; a[num] < 10; a[num]++) {  
            if (visit[a[num]]==false) {  
                visit[a[num]]=true;  
                num = num + 1;  
                dfs(a, visit, num);  
                num = num - 1;  
                visit[a[num]]=false;  
            }  
        }  
    }  


三、下面介绍在蓝桥杯涉及到的题

 

1、反幻方:使用的是上文提到的第一种方法

 

我国古籍很早就记载着

2 9 4 
7 5 3 
6 1 8

这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。

下面考虑一个相反的问题。 
可不可以用 1~9 的数字填入九宫格。 
使得:每行每列每个对角线上的数字和都互不相等呢?

这应该能做到。 
比如: 
9 1 2 
8 4 3 
7 5 6

你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。 
旋转或镜像算同一种。

比如: 
9 1 2 
8 4 3 
7 5 6

7 8 9 
5 4 1 
6 3 2

2 1 9 
3 4 8 
6 5 7

等都算作同一种情况。

请提交三阶反幻方一共多少种。这是一个整数,不要填写任何多余内容。

答案是:3120

下面给出解题代码:

 

public class 反幻方 {
	public static int sum = 0;// 计数器
	public static void fun(int a[], int n) {
		if (n == 9) {
			text(a);
			//return;
		} else
			for (int i = n; i < 9; i++) {
				{
					int temp = a[i];
					a[i] = a[n];
					a[n] = temp;
				}
				fun(a, n + 1);

				{
					int tamp = a[i];
					a[i] = a[n];
					a[n] = tamp;
				}
			}
	}

	public static void text(int a[]) {
		int l1 = a[0] + a[1] + a[2];
		int l2 = a[3] + a[4] + a[5];
		int l3 = a[6] + a[7] + a[8];
		int s1 = a[0] + a[3] + a[6];
		int s2 = a[1] + a[4] + a[7];
		int s3 = a[2] + a[5] + a[8];
		int x1 = a[0] + a[4] + a[8];
		int x2 = a[2] + a[4] + a[6];
		if (l1 != l2 && l1 != l3 && l1 != s1 && l1 != s2 && l1 != s3
				&& l1 != x1 && l1 != x2)
			if (l2 != l3 && l2 != s1 && l2 != s2 && l2 != s3 && l2 != x1
					&& l2 != x2)
				if (l3 != s1 && l3 != s2 && l3 != s3 && l3 != x1 && l3 != x2)
					if (s1 != s2 && s1 != s3 && s1 != x1 && s1 != x2)
						if (s2 != s3 && s2 != x1 && s2 != x2)
							if (s3 != x1 && s3 != x2)
								if (x1 != x2)
									sum++;
	}

	public static void main(String[] args) {
		int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		fun(a, 0);
		System.out.print(sum / 8);
	}
}

2、方格填数:使用的是上文提到的第二种方法

 

如下的10个格子
                    +----+-----+----+
                    |         |        |        |
          +----+-----+----+-----+
          |        |         |         |         |
+----+-----+-----+-----+----+
|        |         |         |
+---+------+----+

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

下面给出解题代码:

 

public class 方格填数 {  
    static int count = 0;  
    public static void main(String[] args) {  
        int a[] = new int[12];  
        boolean visit[] = new boolean[10];//因为只用到了a[1]-a[10];  
        dfs(a,visit,1);  
        System.out.println(count);  
    }  
  
    private static void dfs(int[] a, boolean[] visit, int num) {  
        if (num==11) {  
            if (judge(a)) {  
                count++;  
            }  
            return;  
        }  
        for (a[num] = 0; a[num] < 10; a[num]++) {  
            if (visit[a[num]]==false) {  
                visit[a[num]]=true;  
                num = num + 1;  
                dfs(a, visit, num);  
                num = num - 1;  
                visit[a[num]]=false;  
            }  
        }  
    }  
  
    private static boolean judge(int[] a) {  
        if ((a[1]==a[2]+1||a[1]==a[2]-1)||  
                (a[1]==a[6]+1||a[1]==a[6]-1)||  
                (a[1]==a[5]+1||a[1]==a[5]-1)||  
                (a[1]==a[4]+1||a[1]==a[4]-1)) {  
            return false;  
        }else if ((a[2]==a[5]+1||a[2]==a[5]-1)||  
                (a[2]==a[3]+1||a[2]==a[3]-1)||  
                (a[2]==a[7]+1||a[2]==a[7]-1)||  
                (a[2]==a[6]+1||a[2]==a[6]-1)) {  
            return false;  
        }else if ((a[3]==a[6]+1||a[3]==a[6]-1)||  
                (a[3]==a[7]+1||a[3]==a[7]-1)) {  
            return false;  
        }else if ((a[4]==a[5]+1||a[4]==a[5]-1)||  
                (a[4]==a[8]+1||a[4]==a[8]-1)||  
                (a[4]==a[9]+1||a[4]==a[9]-1)) {  
            return false;  
        }else if ((a[6]==a[7]+1||a[6]==a[7]-1)||  
                (a[6]==a[10]+1||a[6]==a[10]-1)||  
                (a[6]==a[9]+1||a[6]==a[9]-1)) {  
            return false;  
        }else if (a[7]==a[10]+1||a[7]==a[10]-1) {  
            return false;  
        }else if (a[8]==a[9]+1||a[8]==a[9]-1) {  
            return false;  
        }else if (a[9]==a[10]+1||a[9]==a[10]-1) {  
            return false;  
        }else if ((a[5]==a[6]+1||a[5]==a[6]-1)||  
                (a[5]==a[10]+1||a[5]==a[10]-1)||  
                (a[5]==a[9]+1||a[5]==a[9]-1)||  
                (a[5]==a[8]+1||a[5]==a[8]-1)) {  
            return false;  
        }  
        return true;  
    }  
  
}  

答案是:1580
有更好的全排列方法欢迎交流!

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值