例題1:P1088 [NOIP2004 普及組] 火星人
如果採用樸素的方法,每次都把火星人的排列初始化為原始排列再計算次數肯定會 \(\sf TLE\)
#include <bits/stdc++.h>
const int N = 1e4 + 5;
int a[N], b[N];
int n, m, cnt, t;
bool check(int x[], int y[]) {
for (int i = 0; i < n; i++) {
if (x[i] != y[i]) return false;
}
return true;
}
int main()
{
std::cin >> n >> m;
for (int i = 0; i < n; i++) std::cin >> a[i];
for (int i = 0; i < n; i++) b[i] = a[i];
std::sort(b, b + n);
do {
if (check(a, b)) break;
cnt++;
}while(std::next_permutation(b, b + n));
cnt += m;
std::sort(b, b + n);
do {
if (t == cnt) {
for (int i = 0; i < n; i++) std::cout << b[i] << " ";
break;
}
t++;
}while(std::next_permutation(b, b + n));
}
所以應該從當前排列(就是火星人手指表示的那個序列)開始,做 \(m\) 次排列,即找按順序排列的全排列中,排在當前序列之後 \(m\) 個的那個序列。
\(AC\) 程式碼:
#include <cstdio>
#include <algorithm>
const int N = 1e4 + 5;
int a[N], n, m;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
while (m--) std::next_permutation(a, a + n);
for (int i = 0; i < n; i++) printf("%d ", a[i]);
return 0;
}
例題2:HDU 1027
題目大意為輸出序列 \(1 \sim N\) 的第 \(m\) 個全排列。
#include <cstdio>
#include <algorithm>
const int N = 1010;
int a[N];
int n, m, cnt;
int main()
{
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; i++) a[i] = i + 1;
cnt = 0;
do {
if (cnt == m - 1) {
for (int i = 0; i < n; i++) printf("%d ", a[i]);
puts("");
break;
}
cnt++;
}while(std::next_permutation(a, a + n));
}
return 0;
}