全排列算法Java描述 与 实战应用 详解 (有源码)

1、全排列简介
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

公式:全排列数f(n)=n!(定义0!=1),

如 1,2,3 三个元素的全排列为:

1,2,3 、1,3,2、2,1,3、2,3,1、3,1,2、3,2,1 共321=6种。

2、小白求全排列
解释:

如下图的代码,运用continue来剪枝尽可能优化。10个数做全排列花费时间477毫秒,不同的电脑花费的时间不同。
在这里插入图片描述
3、DFS算法求全排列
解释:

采用DFS(深度优先搜索)算法来求全排列,巧妙运用锁来剪枝,还有最重要的是他能保证字典序。DFS的用法非常广泛,例如图的遍历等等。10个数做全排列花费时间306毫秒,不同的电脑花费的时间不同。

如下图中代码基本都有注释,如果没有看懂,需要补递归的知识。
在这里插入图片描述
4、递归交换法求全排列
解释:

采用递归与还原的方式来求全排列,效率非常高,基本上没有多余的步骤,但是他不能保证字典序。如果你发现有比这个效率高的,请在后台私信我。10个数做全排列花费时间54毫秒,不同的电脑花费的时间不同。

如下图中代码基本都有注释,如果没有看懂,需要补递归的知识。
在这里插入图片描述
5、全排列算法实战题目
1、九宫幻方

问题描述

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2
  3 5 7
  8 1 6

有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入格式

输入仅包含单组测试数据。
  每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
  对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

输出格式

如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

样例输入

0 7 2
0 5 0
0 3 0

数据规模和约定

峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 1000ms

import java.util.Scanner;
public class Main {

  static Scanner sc;
  static int count = 0;
  static int[] b;
  public static void main(String[] args) {

    int[] a = {1,2,3,4,5,6,7,8,9};
    b = new int[9];

    sc = new Scanner(System.in);

    for(int i=0;i<b.length;i++){
      b[i] = sc.nextInt(); 
    }

    permutation(a, 0, a.length-1);

    if(count==0){
      System.out.println("Too Many");
    }

  }

  static void permutation(int a[], int start, int end){

    if(start==end){

      if(judge(a)){//符合九宫幻方

        boolean tempjudge = true;

        for(int i=0;i<b.length;i++){
          if(b[i]!=0){
            if(b[i]!=a[i]){
              tempjudge = false;
            }
          }
        }

        if(tempjudge){
          System.out.println(a[0] +" "+ a[1] +" "+ a[2]);
          System.out.println(a[3] +" "+ a[4] +" "+ a[5]);
          System.out.println(a[6] +" "+ a[7] +" "+ a[8]);
          count++;
        }

      }

    }else{
      for(int i=start;i<=end;i++){
        a = swap(a, start, i);
        permutation(a, start+1, end);
        a = swap(a, start, i);
      }
    }

  }

  static int[] swap(int a[], int i, int j){
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
    return a;
  }
  
  static boolean judge(int a[]){
    //行
    int temp1 = a[0] + a[1] + a[2];
    int temp2 = a[3] + a[4] + a[5];
    int temp3 = a[6] + a[7] + a[8];
    if(temp1!=temp2||temp1!=temp3||temp2!=temp3) return false;

    //列
    temp1 = a[0] + a[3] + a[6];
    temp2 = a[1] + a[4] + a[7];
    temp3 = a[2] + a[5] + a[8];
    if(temp1!=temp2||temp1!=temp3||temp2!=temp3) return false;

    //对角线
    temp1 = a[0] + a[4] + a[8];
    temp2 = a[2] + a[4] + a[6];
    if(temp1!=temp2) return false;
    return true;
  }
}

2、带分数

问题描述

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。还可以表示为:100 = 82 + 3546 / 197。

注意特征:

带分数中,数字1~9分别出现且只出现一次(不包含0)。类似这样的带分数,100 有 11 种表示法。

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

样例输入1

100

样例输出1

11

样例输入2

105

样例输出2

6

import java.util.Scanner;

public class Main {
  static int count = 0;
  static int N = 0;
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    N = sc.nextInt();
    
    //long start = System.currentTimeMillis();
    
    int[] a = new int[]{1,2,3,4,5,6,7,8,9};
    
    permu(a, 0, a.length-1);
    System.out.println(count);
    
    //System.out.println(System.currentTimeMillis()-start);
  }
  
  public static void permu(int[] a, int start, int end){
    
    if(start==end){

      out:
      for(int i=0;i<7;i++){//对加号控制
        for(int j=i+1;j<8;j++){//对除号控制
          int x = cut(a, 0, i);//加号前的数
          int y = cut(a, i+1, j);//加号后除号前的数
          int z = cut(a, j+1, 8);//除号后的数
          
          if(x>N){//如果加号前的数大于N就没必要算了
            break out;
          }
          
          if(y<z||y%z!=0){//当后面的y z是小数的时候就没必要查找了
            continue;
          }
          
          int result = x+y/z;//计算出结果
          
          if(result==N){
            count++;
            //System.out.println(x+"+"+y+"/"+z);
          }
          
        }
      }
      
    }else{
      for(int i=start;i<=end;i++){
        a = swap(a, start, i);
        permu(a, start+1, end);
        a = swap(a, start, i);
      }
    }
    
  }
  
  public static int[] swap(int[] a, int i, int j){
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
    return a;
  }
  
  public static int cut(int[] a, int start, int end){
    int temp = 0;
    for(int i=start;i<=end;i++){
      temp = temp*10 + a[i];
    }
    return temp;
  }
  
}
发布了0 篇原创文章 · 获赞 0 · 访问量 589

猜你喜欢

转载自blog.csdn.net/qq_41490913/article/details/105021103