题目描述
牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10 个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。
输入描述:
每个输入包含一个测试用例。每个测试用例的第一行包含两个整数 n 和 k(1 <= n <= 100, 0 <= k <= 1000000000),接下来的 1 行,包含 n 个数字表示排列 A,其中等于0的项表示看不清的位置(不超过 10 个)。
输出描述:
输出一行表示合法的排列数目。
示例1
输入
5 5 4 0 0 2 0
输出
2
题目链接
法一:dfs,惊奇的过了。全排列的变形,具体如下。代码如下(耗时25ms):
1 public class Main { 2 3 //vis标记已经排列的数1~n,不是标记已经排列的下标!!! 4 static boolean[] vis = null; 5 //记录每一个可能的排列数列 6 static int[] res = null; 7 //最后将符合标准的排列计数 8 static int cnt = 0; 9 10 public static void main(String[] args) throws IOException { 11 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 12 String line = in.readLine(); 13 String[] s = line.split(" "); 14 int n = Integer.parseInt(s[0]), k = Integer.parseInt(s[1]); 15 line = in.readLine(); 16 s = line.split(" "); 17 vis = new boolean[n + 1]; 18 res = new int[n + 1]; 19 //初始化标记数组和结果数组,注意以下这里的下标,开始从1开始了 20 for(int i = 0; i < n; i++) { 21 if(!s[i].equals("0")) { 22 res[i + 1] = Integer.parseInt(s[i]); 23 vis[res[i + 1]] = true; 24 } 25 } 26 dfs(1, n, k); 27 System.out.println(cnt); 28 } 29 private static void dfs(int x, int n, int k) { 30 //递归终点 31 if(x == n + 1) { 32 int num = 0; 33 //校验标准是否通过,即i<j且a[i]<a[j],且对数是k 34 for(int i = 1; i < n; i++) { 35 for(int j = i + 1; j < n + 1; j++) { 36 if(res[i] < res[j]) { 37 num++; 38 } 39 } 40 } 41 //如果标准通过,计数cnt 42 if(num == k) { 43 cnt++; 44 } 45 return; 46 } 47 //如果初始已经有值,则直接dfs下一个位置,类似于数独的初始化 48 if(res[x] != 0) { 49 dfs(x + 1, n, k); 50 } 51 //这里的i表示可排列的1~n的元数据,因为没有用数组存起来,所以这里直接从1开始 52 for(int i = 1; i <= n; i++) { 53 //校验当前数据是否已经在排列中,如果不在排列中,则放入排列即可 54 if(vis[i] == false) { 55 vis[i] = true; 56 res[x] = i; 57 dfs(x + 1, n, k); 58 res[x] = 0; 59 vis[i] = false; 60 } 61 } 62 } 63 64 }