数字全排列
对于给定的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
题目链接
题目
题目大意
- 给定数字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
题目
题目大意
给定四个单独的数字,任意排列组合成新的数字,并按照从小到大的顺序排列
思路 & 代码
-
将四个数字组合起来,可以使用全排列的思想,不过,如果四个数字全排列开头是0,那么就跳过,不用输出
-
在全排列之前要对数组进行排序
-
如果四个数字是,2 3 1 1,本题中需要考虑去重,即2311这个数只出现一次
-
输出格式要特别注意
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;
}
}
}
}