【数字全排列】 HDU 1027、1716 Java实现


数字全排列

对于给定的n,要求输出从1到n的所有数字的全排列

import java.util.Scanner;

public class FullPerm {

	//从1-n的全排列
    int n;

	//存储数字具体的排列方式
    int[] data;

	//标记数组,如果数字1已经被选过了,那么vis[1]=true
	//如果数字1没有被选过,那么vis[1]=false
    boolean[] vis;

    //cnt用于记录有多少种排列组合方式
    int cnt;

    public static void main(String[] args) {
        new FullPerm().fullPerm();
    }


    public void fullPerm() {

        Scanner in = new Scanner(System.in);

        //n表示从1到n的数字进行全排列
        while ((n = in.nextInt()) != -1) {

            data = new int[n];

            vis = new boolean[n + 1];

            cnt = 0;

            dfs(0);

            System.out.println("有"+cnt+"种排列方式");
        }

    }

    /**
     * @param pos 当前设置值的位置
     */
    private void dfs(int pos) {
        if (pos == n) {
            cnt++;
            print();
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) {
                data[pos] = i;
                vis[i] = true;
                dfs(pos + 1);
                vis[i] = false;
            }
        }
    }

    private void print() {
        for (int i = 0; i < n; i++) {
            System.out.print(data[i]);
        }
        System.out.println();
    }
}

题目一 HDU 1027

题目链接

HDU OJ 1027

题目

在这里插入图片描述

题目大意

  • 给定数字n,表示全排列所用到的数字是:1 ~ n
  • 给定数字m,表示要求第m个全排列是什么

思路 & 代码

那就是按照全排列的思路,从第一种全排列到第m种全排列全部计算一遍,到第m种全排列时,把这一次的排列方式输出,然后return。

使用数字全排列的方法,增加一个变量cnt,用于计算当前这种排列方式是所有全排列中的第几个

import java.util.Scanner;

public class Main {

    int n;
    int m;
    int[] data;
    boolean[] vis;

    //cnt用于记录有多少种排列组合方式
    int cnt;

    public static void main(String[] args) {
        new Main().fullPerm();
    }


    public void fullPerm() {

        Scanner in = new Scanner(System.in);

        //n表示从1到n的数字进行全排列
        while (in.hasNext()) {

            //有n个数字的全排列
            n = in.nextInt();

            //求第m个全排列
            m = in.nextInt();
            //data数组用于存放排列的数字

            data = new int[n];

            //vis[i],表示第i个位置上的数组是否使用过,使用了,vis[i]=true,没使用,vis[i]=false
            vis = new boolean[n + 1];

            cnt = 0;

            dfs(0);

        }

    }

    /**
     * @param pos 当前设置值的位置
     */
    private void dfs(int pos) {
        if (cnt >= m) {
            return;
        }
        if (pos == n) {
            cnt++;
            if (cnt == m) {
                print();
            }
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) {
                data[pos] = i;
                vis[i] = true;
                dfs(pos + 1);
                vis[i] = false;
            }
        }
    }

    private void print() {
        for (int i = 0; i < n; i++) {
            if (i != 0) {
                System.out.print(" ");
            }
            System.out.print(data[i]);
        }
        System.out.println();
    }
}

题目二 HDU 1716

题目链接

https://acm.hdu.edu.cn/showproblem.php?pid=1716

题目

在这里插入图片描述

题目大意

给定四个单独的数字,任意排列组合成新的数字,并按照从小到大的顺序排列

思路 & 代码

  1. 将四个数字组合起来,可以使用全排列的思想,不过,如果四个数字全排列开头是0,那么就跳过,不用输出

  2. 在全排列之前要对数组进行排序

  3. 如果四个数字是,2 3 1 1,本题中需要考虑去重,即2311这个数只出现一次

  4. 输出格式要特别注意

import java.util.Arrays;
import java.util.Scanner;

public class Main {

    int n;
    int m;
    int[] data;
    boolean[] vis;
    int[] res;

    //flag用于标识当前输出行的第一位数字
    int flag;

    public static void main(String[] args) {
        new Main().fullPerm();
    }


    public void fullPerm() {

        Scanner in = new Scanner(System.in);

        boolean f = false;
        //n表示从1到n的数字进行全排列
        while (in.hasNext()) {

            data = new int[4];
            vis = new boolean[4];
            res = new int[4];
            flag = -1;

            for (int i = 0; i < 4; i++) {
                data[i] = in.nextInt();
            }
            if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) {
                return;
            }

            Arrays.sort(data);

            //不同样例之间输出换行,第一次不用
            if (f) {
                System.out.println();
            }
            f = true;

            dfs(0);
            System.out.println();

        }

    }

    /**
     * @param pos 当前设置值的位置
     */
    private void dfs(int pos) {

        if (pos == 4) {

            if (res[0] == 0) {
                return;
            }
            //第一次输出
            if (flag == -1) {
                flag = res[0];
                System.out.print(res[0] + "" + res[1] + "" + res[2] + "" + res[3]);
            }
            //表示首位数字相同
            else if (res[0] == flag) {
                System.out.print(" " + res[0] + "" + res[1] + "" + res[2] + "" + res[3]);
            } else {
                System.out.println();
                System.out.print(res[0] + "" + res[1] + "" + res[2] + "" + res[3]);
                flag = res[0];
            }

        }

        for (int i = 0; i < 4; i++) {
            if (i != 0 && data[i - 1] == data[i] && vis[i - 1]) {
                continue;
            }
            if (!vis[i]) {
                res[pos] = data[i];
                vis[i] = true;
                dfs(pos + 1);
                vis[i] = false;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值