UVA - 12335 Lexicographic Order (第k大排列)

求第k小排列算法
本文介绍了一种求解特定字符集第k个字典序排列的方法,通过递归确定每个位置上的字符,适用于字符数量不多于20的情况。文章提供了一个C++实现示例。

Description

Download as PDF

A

Lexicographic Order

Input: Standard Input

Output: Standard Output

 

The alphabet of a certain alien language consists of n distinct symbols. The symbols are like the letters of English alphabet but their ordering is different. You want to know the original order of the symbols in that particular alphabet. You have a string consists of all the letters of that alphabet and you know that this is the k-th (1 based) lexicographic permutation of these symbols. You have to arrange these symbols in lexicographic order of that language.

 

Input

The first line of input will contain an integer T (T ≤ 5000) which denotes the number of test cases.

 

Each of the following T lines contains a string s and an integer k. The string will be of length n (1 ≤ n ≤ 20) and will consist of lowercase letters only. All the letters in the string will be distinct. The value of k will be in the range (1 ≤ k ≤ n!).

 

Output

For each line of input output the case number and a string which contains the letters in lexicographic order in that language.

 

Sample Input                              Output for Sample Input

3
bdac 11
abcd 5
hjbrl 120

Case 1: abcd
Case 2: acdb
Case 3: lrbjh

题意:求第n大的排列

思路:举个简单的例子:序列:1234,求第11个排列,假设我们确定了第一个,那么剩下3个的排列数是3!,因为12是大于6的,所以我们不能放1放到第一个,当我们放2的时候,这个数能有的排列会到12<=12,所以我们就能确定第一个是2了,依次类推

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
using namespace std;
const int maxn = 30;

char str[maxn], ans[maxn];
int n, vis[maxn], ind[maxn]; 

ll cal(int x) {
	ll tmp = 1;
	for (int i = 2; i <= x; i++)
		tmp *= i;
	return tmp;
}

void dfs(int cur , ll dir) {
	if (cur == n)
		return;
	ll tmp = cal(n-cur-1);
	for (int i = 0; i < n; i++) {
		if (vis[i])
			continue;
		if (dir > tmp)
			dir -= tmp;
		else {
			vis[i] = 1;
			ind[cur] = i;
			dfs(cur+1, dir);
			return;
		}

	}
}

int main() {
	ll x;
	int t, cas = 1;
	scanf("%d", &t);
	while (t--) {
		scanf("%s%lld", str, &x);
		n = strlen(str);
		memset(vis, 0, sizeof(vis));
		dfs(0, x);
		printf("Case %d: ", cas++);
		for (int i = 0; i < n; i++)
			ans[ind[i]] = str[i];
		for (int i = 0; i < n; i++)
			printf("%c", ans[i]);
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值