蓝桥杯-排列问题(50分)

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(对象)”这是不能用的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值