P2524 Uim的情人节礼物·其之弐 [洛谷]
1.题目
题目描述
Uim成功地按照顺序将礼物送到了N个妹子的手里并维持她们的和谐。
Uim现在想知道,他最终选择的顺序是所有给N个妹子送礼顺序中、字典序第几小的。
输入格式
第一行一个整数N,表示有N个数。
第二行一个整数X,表示给出的排列。
输出格式
一个整数,表示是第几小的字典序。
样例输入 #1
3
231
样例输出 #1
4
提示
1<=N<=9
输入的排列没有空格
2.分析
思路:
①next_permutation
②prev_permutation
③康托展开
④dfs
3.代码
1.next_permutation()
找到该排列的下一个排列
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm> //next_permuation
vector <int> a,b;
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
a.push_back(i);
for (int i = 0; i < n; ++i)
{
char t;
cin >> t;
b.push_back(t - '0');
}
int cnt = 1;
while (a != b)
{
next_permutation(a.begin(), a.end());
cnt++;
}
cout << cnt;
return 0;
}
2.prev_permutation()
找到该排列的上一个排列
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm> //prev_permuation
vector <int> a;
int main()
{
int n;
scanf("%d", &n);
string s;
cin >> s;
for (auto x : s)
a.push_back(x - '0');
int cnt = 1;
while (prev_permutation(a.begin(), a.end()))
cnt++;
cout << cnt;
return 0;
}
3.康托展开
//康托展开 这里只说明用法
//X = a[n] * [(n - 1)!] + a[n - 1] * [(n - 2)!] + .... + a[1] * [0!]
//X为比当前排列小的序列个数 a[i]表示i右侧比i位置小的数字个数
#include <iostream>
using namespace std;
int a[10];
int fac(int n) //n的阶乘大小
{
if (n == 1) return 1;
return n * fac(n - 1);
}
int cantor(int n) //康托展开
{
int res = 0, cnt = 0;
//从前向后判断
for (int i = 1; i < n; ++i) //最后一位不用判断,固定为0
{
for (int j = i + 1; j <= n; j++)
if (a[j] < a[i])
cnt++;
res += cnt * fac(n-i);
cnt = 0; //计数器清零
}
return res+1; //res为比当前小的序列个数,则当前序列为第res+1小的序列
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
char c;
cin >> c;
a[i] = c - '0';
}
cout << cantor(n);
return 0;
}
4.dfs
搜索每一种排列,并每次与原序列比较
//dfs
#include <iostream>
using namespace std;
int path[10]; //记录路径
bool st[10]; //是否使用过某个数字
int n;
int a[10]; //初始序列
int cnt;
bool same_seq() //判断是否是同一个序列
{
++cnt; //每次调用都要++
for (int i = 0; i < n; ++i)
if (path[i] != a[i])
return false;
return true;
}
void dfs(int u) //u为下标
{
if (u == n) //走到尾了
{
if (same_seq()) cout << cnt;
return;
}
for (int i = 1; i <= n; ++i)
{
if (!st[i]) //未被使用
{
path[u] = i;
st[i] = true;
dfs(u + 1); //搜索下一个位置
st[i] = false; //回溯
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; ++i)
{
char c;
cin >> c;
a[i] = c - '0';
}
dfs(0);
return 0;
}
4.总结
库函数~
5.更新日志
2022.8.7
欢迎交流、讨论、指正~
不正确、不理解之处欢迎评论留言~