package exec;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;
/**
问题描述
求一个0~N-1的排列(即每个数只能出现一次),给出限制条件(一张N*N的表,第i行第j列的1或0,表示为j-1这个数不能出现在i-1这个数后面,并保证第i行第i列为0)。
将这个排列看成一个自然数,求从小到大排序第K个排列。
数据规模和约定
N<=10,K<=500000
输入格式
第一行为N和K,接下来的N行,每行N个数,0表示不能,1表示能
输出格式
所求的排列
样例输入
3 2
0 1 1
1 0 0
0 1 0
样例输出
1 0 2
解释:
对于N=3的没有任何限制的情况
第一:0 1 2
第二:0 2 1
第三:1 0 2
第四:1 2 0
第五:2 0 1
第六:2 1 0
根据题目所给的限制条件由于2不能出现在1后面,0不能出现在2后面
第一:0 2 1
第二:1 0 2
第三:2 1 0
* @author Vivinia
*
* 2018年2月8日
*/
public class F {
static int sum=0,temp=0;
static LinkedList<L> list; //两个int元素,代表left不能再right前边
static int k;
public static void main(String[] args) {
list=new LinkedList<L>();
Scanner input=new Scanner(System.in);
int n=input.nextInt();
k=input.nextInt();
int[][] num=new int[n][n];
int[] arr1=new int[n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
num[i][j]=input.nextInt();
input.close();
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(i!=j&&num[i][j]==0) { //0代表j不可以在i后边
list.add(new L(i,j));
}
}
}
for(int i=0;i<n;i++)
arr1[i]=i; //0到n-1存入数组
perm(arr1,0,n); //数组,起始位置,长度
}
private static void perm(int[] arr1, int j, int n) { //数组全排列
if (j < n - 1) {
int i, t;
for (i = j; i < n; i++) {
t = arr1[j];
arr1[j] = arr1[i];
arr1[i] = t;
perm(arr1, j + 1, n);
t = arr1[j];
arr1[j] = arr1[i];
arr1[i] = t;
}
} else {
int i;
int flag=0;
for (i = 0; i < n-1; i++) {
for(int t=0;t<list.size();t++) {
if(list.get(t).getLeft()==arr1[i]&&list.get(t).getRight()==arr1[i+1]) { //如果数组全排列中有两个连续的数据和之前的list集合中某两个元素相等
flag=1; //标志位,代表是通过break退出的循环
break; //跳出循环,代表这组排列作废
}
}
if(flag==1) //如果内层循环是break出来的,这个循环液break出去
break;
}
if(i==n-1&&flag==0) //遍历完没有break,这组符合条件,个数加1
sum++;
if(sum==k&&temp==0) { //temp标志位用来标记sum==k是否输出,因为递归调用如果不设置标志位有可能会再次进入
temp=1;
for(i=0;i<n;i++)
System.out.print(arr1[i]+" ");
System.out.println();
return;
}
}
}
}
class L{
int left;
int right;
public L(int left, int right) {
super();
this.left = left;
this.right = right;
}
public int getLeft() {
return left;
}
public void setLeft(int left) {
this.left = left;
}
public int getRight() {
return right;
}
public void setRight(int right) {
this.right = right;
}
}
1.两组数据通过了一组,不太清楚是什么原因,不知道是不是数组排列顺序的事,因为这个题最终顺序和数组全排列顺序有关,这个我一直不是很理解;
2.小知识点很多,比较散,该设置标志位就设置标志位,很有用;
3.关于一个对象是否存在一个集合中,貌似只能遍历出来然后一个一个比较,“集合.contains(对象)”这是不能用的;