全排列+check检验

通过这几天的刷题,发现蓝桥惯出的一种题型----全排列+check()。
也就是在求出所有全排列的结果后,并检查每种结果是否满足题目的条件得出最终答案。

一、核心

递归式全排列或字典序式全排列
补:有重复元素求全排列,要求结果不重复时,要用字典序求解,递归求解会重复的(eg:前两个元素相同,第二个元素和第一个元素交换位置的排列结果和第一种结果相同)。

二、代码实现

1.递归式(未按字典序输出)

import java.util.Scanner;

public class Permutations {
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int[] arr=new int[n];
		for (int i = 0; i < arr.length; i++) {
			arr[i]=i+1;
		}
		permutation(arr,0);
	}

	private static void permutation(int[] arr, int start) {
		if (start==arr.length) {
			for (int i = 0; i < arr.length; i++) {
				System.out.print(arr[i]+" ");
			}
			System.out.println();
		}
		for (int i = start; i < arr.length; i++) {
			swap(arr, start, i);
			permutation(arr, start+1);
			swap(arr, start, i);
		}
	}
	
	private static void swap(int[] arr,int i,int j) {
		int t=arr[i];
		arr[i]=arr[j];
		arr[j]=t;
	}
}

2.字典序

import java.util.Scanner;

public class PermutationsWithDictionary {
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int[] arr=new int[n];
		for (int i = 0; i < arr.length; i++) {
			arr[i]=in.nextInt();
		}
		permutation(arr);
	}

	private static void permutation(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i]+" ");
		}
		System.out.println();
		while (true) {
			int index1=-1;
			int index2=-1;
			for (int i = arr.length-2; i >=0; i--) {
				if (arr[i]<arr[i+1]) {
					index1=i;
					break;
				}
			}
			if (index1==-1) {
				return;
			}
			for (int i = arr.length-1; i >=index1+1; i--) {
				if (arr[i]>arr[index1]) {
					index2=i;
					break;
				}
			}
			swap(arr, index1, index2);
			reverse(arr,index1+1,arr.length-1);
			for (int i = 0; i < arr.length; i++) {
				System.out.print(arr[i]+" ");
			}
			System.out.println();
		}
	}
	private static void reverse(int[] arr, int left,int right) {
		for (int i = left,j=right; i < j; i++,j--) {
			swap(arr, i, j);
		}
	}

	private static void swap(int[] arr,int i,int j) {
		int t=arr[i];
		arr[i]=arr[j];
		arr[j]=t;
	}
}

三、历年真题

注:前面的标号对应于该题在竞码平台的题目id
7005 寒假作业
7006 剪邮票
7011 凑算式
7019 搭积木

1.寒假作业

package lanqiaobei_page1;

import java.util.Scanner;

public class T7005 {
	static int ans = 0;

	public static void main(String[] args) {
		int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
		permutation(arr, 0);
		System.out.println(ans);
	}

	private static void permutation(int[] arr, int start) {
		if (start == arr.length) {
			if (check(arr)) {
				ans++;
			}
		}
		for (int i = start; i < arr.length; i++) {
			swap(arr, i, start);
			permutation(arr, start + 1);
			swap(arr, i, start);
		}
	}

	private static void swap(int[] arr, int i, int j) {
		int t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}

	private static boolean check(int[] ia) {
		if (ia[0] + ia[1] == ia[2] && ia[3] - ia[4] == ia[5] && ia[6] * ia[7] == ia[8] && ia[10] * ia[11] == ia[9]) {
			return true;
		}
		return false;
	}
}

2.剪邮票

package lanqiaobei_page1;
//有一定难度,涉及到全排列和检查连通性。(以及一维数组如何转成二维数组)
//题型:有相同元素的数组求没有重复结果的全排列。
public class T7006 {
	static int ans = 0;
	public static void main(String[] args) {
//		注意第一个数组要是字典序最小的那个。
//		用字典序求出来的全部排列是不重复的,所以这道题要用这个方法求解,用递归求出的所有排列有重复的,结果当然也会重复。
		int[] ia= {0,0,0,0,0,0,0,1,1,1,1,1};
		permutation(ia);
		System.out.println(ans);
	}

	private static void permutation(int[] arr) {
		int[][] temp=new int[3][4];
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 4; j++) {
				temp[i][j]=arr[i*4+j];
			}
		}
//		第一个排列,转换成二维数组后,检查是否只有一个连通图。
		if (check(temp)) {
			ans++;
		}
		
		while (true) {
			int index1=-1;
			int index2=-1;
			for (int i = arr.length-2; i >=0; i--) {
				if (arr[i]<arr[i+1]) {
					index1=i;
					break;
				}
			}
			if (index1==-1) {
				return;
			}
			for (int i = arr.length-1; i >=index1+1; i--) {
				if (arr[i]>arr[index1]) {
					index2=i;
					break;
				}
			}
			swap(arr, index1, index2);
			reverse(arr,index1+1,arr.length-1);
			for (int i = 0; i < 3; i++) {
				for (int j = 0; j < 4; j++) {
					temp[i][j]=arr[i*4+j];
				}
			}
			if (check(temp)) {
				ans++;
			}
		}
	}
	
	private static boolean check(int[][] map) {
		int cnt=0;
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				if (map[i][j]==1) {
					dfs(map,i,j);
					cnt++;
				}
			}
		}
		if (cnt==1) {
			return true;
		}
		return false;
	}

	private static void dfs(int[][] map, int i, int j) {
		int row=map.length;
		int col=map[0].length;
		map[i][j]=0;
		if (i-1>=0 && map[i-1][j]==1) dfs(map, i-1, j);
		if (i+1<row && map[i+1][j]==1) dfs(map, i+1, j);
		if (j-1>=0 && map[i][j-1]==1) dfs(map, i, j-1);
		if (j+1<col && map[i][j+1]==1) dfs(map, i, j+1);
	}

	private static void swap(int[] arr, int i, int j) {
		int t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
	private static void reverse(int[] arr, int left,int right) {
		for (int i = left,j=right; i < j; i++,j--) {
			swap(arr, i, j);
		}
	}
}

3.凑算式

package lanqiaobei_page1;
//想错了,结果应该是通分后整除的结果是10,误想成了每个结果四舍五入后之和是10
import java.util.Scanner;

public class T7011 {
	static int ans = 0;

	public static void main(String[] args) {
		int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		permutation(arr, 0);
		System.out.println(ans);
	}

	private static void permutation(int[] arr, int start) {
		if (start == arr.length) {
			if (check(arr)) {
				ans++;
			}
		}
		for (int i = start; i < arr.length; i++) {
			swap(arr, start, i);
			permutation(arr, start + 1);
			swap(arr, start, i);
		}
	}

	private static boolean check(int[] arr) {
		int fenzi=arr[3] * 100 + arr[4] * 10 + arr[5];
		int fenmu=arr[6] * 100 + arr[7] * 10 + arr[8];
		if ((arr[1]*fenmu+arr[2]*fenzi)%(arr[2]*fenmu)==0 && arr[0]+(arr[1]*fenmu+arr[2]*fenzi)/(arr[2]*fenmu)==10) {
			return true;
		}
		return false;
	}

	private static void swap(int[] arr, int i, int j) {
		int t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
}

4.搭积木

package lanqiaobei_page1;

public class T7019 {
	static int ans=0;
	public static void main(String[] args) {
		int[] arr=new int[] {0,1,2,3,4,5,6,7,8,9};
		permutation(arr,0);
		System.out.println(ans);
	}

	private static void permutation(int[] arr, int start) {
		if (start==arr.length) {
			if (check(arr)) {
				ans++;
			}
		}
		for (int i = start; i < arr.length; i++) {
			swap(arr,i,start);
			permutation(arr, start+1);
			swap(arr,i,start);
		}
	}

	private static boolean check(int[] arr) {
		if (arr[0]<arr[1] && arr[0]<arr[2] && arr[1]<arr[3] && arr[1]<arr[4] && arr[2]<arr[4] 
		&& arr[2]<arr[5] && arr[3]<arr[6] && arr[3]<arr[7] && arr[4]<arr[7] && arr[4]<arr[8] 
		&& arr[5]<arr[8] && arr[5]<arr[9] ) {
			return true;
		}
		return false;
	}

	private static void swap(int[] arr, int i, int j) {
		int t=arr[i];
		arr[i]=arr[j];
		arr[j]=t;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值