当前位置: 首页 > news >正文

信息学奥赛一本通 1929:【04NOIP普及组】火星人 | 洛谷 P1088 [NOIP 2004 普及组] 火星人

【题目链接】

ybt 1929:【04NOIP普及组】火星人
洛谷 P1088 [NOIP 2004 普及组] 火星人

【题目考点】

1. 深搜回溯
2. STL next_permutation函数

头文件<algorithm>
函数定义:next_permutation(lb, ub, cmp)
lb:区间下界,为指针或迭代器
ub:区间上界,为指针或迭代器
cmp:函数或仿函数,指定比较规则,默认为less仿函数。
使区间[lb, ub)范围内的元素变为其下一个排列,复杂度为 O ( n ) O(n) O(n)

如果不传参数cmp,对整型序列取其下一个排列,其下一个排列就是将[lb, ub)区间内元素的全排列按字典序升序给出后,当前序列的下一个序列。

【解题思路】

火星人的手指排列就是一个1到n的排列,该排列表示的数就是该排列在按字典序排序的1到n的全排列中是第几个排列
要想使该排列表示的数加上m,而后得到手指序列,就是要取按字典序排序的在1到n的全排列中,当前排列后的第m个排列。

解法1:深搜回溯

深搜求全排列是深搜回溯的模板题,相信各位同学都会写的。

#include <bits/stdc++.h>
using namespace std;
int num[10005], n, m;
bool vis[10005];
void dfs(int k)
{
	if(k > n)
    {
        for(int i = 1; i <= n; ++i)
            cout << num[i] << ' ';
        cout << '\n';
        return;
    }
    for(int i = 1 ; i <= n; ++i) if(!vis[i])
    {
        num[k] = i;
        vis[i] = true;
        dfs(k + 1);
        vis[i] = false;
    }
}
int main()
{
    cin >> n >> m;
    dfs(1);
    return 0;
}

而现在是需要从深搜回溯求全排列的中间某状态出发,向后继续搜索,搜索到第m个排列时输出。

这个过程好比一个话剧,一开始就要从第二幕开始演,那么需要直接布置第二幕的舞台,相关演员也要好像第一幕都演完了的一样,直接开始第二幕演出。而不需要重新从第一幕开始演。

当前num数组的初值实际是通过输入得到的。我们需要让num数组当前的值是通过搜索得到的。
这是一个预先处理的过程,设bool类型量pre,初值为真,pre为真表示当前在进行预处理,使整个dfs过程达到刚好搜索出输入的num序列的状态。
调用dfs(1),搜索确定第一个数的值,如果第1个数的值是num[1],那么此时i循环到的值应该是num[1]
递归调用dfs(2),搜索确定第二个数的值,如果第2个数的值是num[2],那么此时i循环到的值应该是num[2]

调用dfs(k)时,确定第k个数是num[k],那么该次调用中i应该循环到num[k]。因此在dfs(k)中,for循环i的初值应该设为num[k]
k>n时,进入搜索的递归出口,此时应该结束预处理,将pre设为假。
而后就开始正常的搜索排列的过程,非预处理状态下for循环i的初值应该为1。
设计数变量ct,每搜索到一个排列计数增加1。当计数达到m时,找到了输入序列后的第m序列,将其输出,而后结束递归。

解法2:使用next_permutation

STL中的next_permutation可以取一个序列的下一个排列。循环m次,每次循环取下一个排列,再将序列输出,即为结果。

【题解代码】

解法1:深搜回溯
#include <bits/stdc++.h>
using namespace std;
int num[10005], n, m, ct;
bool vis[10005], isPre = true;//isPre:是否在进行预处理 
void dfs(int k)
{
	if(k > n)
    {
    	if(isPre)
    	{
    		isPre = false;
    		return;
		}
        if(++ct == m)//如果已经搜索到后面第m个排列,则输出结果 
        {
            for(int i = 1; i <= n; ++i)
                cout << num[i] << ' ';
        }
        return;
    }
    if(ct == m)//ct为m表示已经输出结果,结束搜索 
        return;
    for(int i = isPre ? num[k] : 1 ; i <= n; ++i) if(!vis[i])
    {
        num[k] = i;
        vis[i] = true;
        dfs(k + 1);
        vis[i] = false;
    }
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)
        cin >> num[i];
    dfs(1);
    return 0;
}
解法2:使用next_permutation
#include <bits/stdc++.h>
using namespace std;
#define N 10005
int n, m, a[N];
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> a[i];
	for(int i = 1; i <= m; ++i)
		next_permutation(a+1, a+1+n);
	for(int i = 1; i <= n; ++i)
		cout << a[i] << ' ';
    return 0;
}

相关文章:

  • MIME类型
  • Android中的libs.versions.toml文件
  • Sentinel核心源码分析(下)
  • Python----PaddlePaddle(深度学习框架PaddlePaddle,概述,安装,衍生工具)
  • 红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn
  • 武汉迅狐科技:AI赋能企业营销,打造智能获客新范式
  • 【软件系统架构】分布式架构
  • 六种蝴蝶昆虫分类-图像分类数据集
  • 【力扣hot100题】(067)寻找两个有序数组的中位数
  • 壹起航:15 年深耕,助力中国工厂出海远航产品出海
  • Valgrind——内存调试和性能分析工具
  • 蓝桥杯真题——前缀总分、遗迹
  • el-table,新增、复制数据后,之前的勾选状态丢失
  • 【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3源码整体结构解析
  • 系统与网络安全------Windows系统安全(11)
  • 【笔记】VS中C#类库项目引用另一个类库项目的方法
  • coze生成流程图和思维导图工作流
  • 【C#知识点详解】Dictionary<TKey,TValue>储存结构详解
  • 初阶数据结构(3)顺序表
  • Electron使用WebAssembly实现CRC-32 STM32校验
  • 定制网站建设公司/seo基础课程
  • 一般网站如何做防采集的/广州网站运营专注乐云seo
  • 自助网站建设系统/百度竞价运营
  • 加工厂网站建设/信息流广告的特点
  • 西安市规划建设局网站/爱站网关键词挖掘查询
  • 湘潭网站制作公司/南宁今日头条最新消息