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


    1.题目

    题目链接

    题目描述

    Uim成功地按照顺序将礼物送到了N个妹子的手里并维持她们的和谐。

    Uim现在想知道,他最终选择的顺序是所有给N个妹子送礼顺序中、字典序第几小的。

    输入格式

    第一行一个整数N,表示有N个数。

    第二行一个整数X,表示给出的排列。

    输出格式

    一个整数,表示是第几小的字典序。

    样例输入 #1

    3
    231
    
    • 1
    • 2

    样例输出 #1

    4
    
    • 1

    提示
    1<=N<=9
    输入的排列没有空格

    2.分析

    思路:
    ①next_permutation
    ②prev_permutation
    ③康托展开
    ④dfs

    3.代码

    1.next_permutation()

    找到该排列的下一个排列

    #include 
    using namespace std;
    #include 
    #include   //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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2.prev_permutation()

    找到该排列的上一个排列

    #include 
    using namespace std;
    #include 
    #include   //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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.康托展开

    百度百科:康托展开 跳转链接

    //康托展开 这里只说明用法
    //X = a[n] * [(n - 1)!] + a[n - 1] * [(n - 2)!] + .... + a[1] * [0!]
    //X为比当前排列小的序列个数  a[i]表示i右侧比i位置小的数字个数
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    4.dfs

    搜索每一种排列,并每次与原序列比较

    //dfs
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4.总结

    库函数~

    5.更新日志

    2022.8.7

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

  • 相关阅读:
    Linux——(第十一章)软件包管理
    前端面试官必备-面试宝典HTML与CSS
    【英语:基础进阶_语法进阶提升】F4.名词性从句
    LintCode 1169: Permutation in String 字符串处理好题
    动态规划:03爬楼梯
    如何写砸一本小说
    Mysql 讲解所有的约束类型
    图的几个基本概念:连通图、强连通图、完全图等
    无涯教程-JavaScript - CONFIDENCE.NORM函数
    Vue路由
  • 原文地址:https://blog.csdn.net/qq_60404548/article/details/126217795