DHUOJ 排列问题

排列问题

时间限制: 1S类别: 搜索->中等

问题描述 :

  求一个0~N-1的排列(即每个数只能出现一次),给出限制条件(一张N*N的表,第i行第j列的1或0,表示为j这个数能不能出现在i这个数后面,并保证表中的第i行第i列为0,i和j都从0开始),将这个排列看成一个自然数,求从小到大排序第K个排列。

样例输入

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

输入说明 :

  第一行为N和K,接下来的N行,每行N个数,0表示不能,1表示能

       N<=10,K<=500000

输出说明 :

  所求的排列

输入范例 :

3 2
0 1 1
1 0 0
0 1 0

输出范例 :

1 0 2


思路:

先对限制条件进行转换 写出一个筛选已有排列是否满足条件的函数

然后dfs得到全排列,每得到一个排列可以筛一次,计数达到k时,对其输出


代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<iomanip>
#include<vector>
#include<string>
#include<set>
#include<utility>
using namespace std;
int n, k, m = 0;
bool vis[15];
int path[15];
int condition[15][2];

//筛选函数
bool check(int path[], int condition[][2]) {//condition[][1]不能在condition[][0]后面,否则fasle
	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j < m; j++) {
			if (path[i] == condition[j][0] && path[i + 1] == condition[j][1])
				return false;
		}
	}
	return true;
}

void dfs(int u, int& k) {
	if (u == n) {//dfs到底,得到一个排列序列,判断该序列是否符合条件
		if (check(path, condition)) {
			k--;
			if (k == 0) {
				for (int i = 0; i < n; i++) {
					cout << path[i];
					if (i != n - 1)
						cout << ' ';
				}
				cout << endl;
			}
		}
		return;
	}

	//继续dfs加入元素得到排列序列
	for (int i = 0; i < n; i++) {
		if(!vis[i]) {
			path[u] = i;
			vis[i] = true;
			dfs(u + 1, k);
			vis[i] = false;
		}
	}
}

int main() {

	cin >> n >> k;
	int limit[15][15];

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> limit[i][j];
			if (limit[i][j] == 0 && i != j) {//存储筛选条件
				condition[m][0] = i;
				condition[m][1] = j;
				m++;
			}
		}
	}
	dfs(0, k);
	return 0;

}

运行结果截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值