0
点赞
收藏
分享

微信扫一扫

P2524 Uim的情人节礼物·其之弐 [洛谷]


P2524 Uim的情人节礼物·其之弐 [洛谷]

  • ​​1.题目​​
  • ​​2.分析​​
  • ​​3.代码​​
  • ​​1.next_permutation()​​
  • ​​2.prev_permutation()​​
  • ​​3.康托展开​​
  • ​​4.dfs​​
  • ​​4.总结​​
  • ​​5.更新日志​​

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

欢迎交流、讨论、指正~
不正确、不理解之处欢迎评论留言~


举报

相关推荐

0 条评论