首页 > 其他分享 >洛谷题单指南-暴力枚举-P1088 [NOIP2004 普及组] 火星人

洛谷题单指南-暴力枚举-P1088 [NOIP2004 普及组] 火星人

时间:2024-01-31 16:55:39浏览次数:38  
标签:NOIP2004 火星人 return int 洛谷题 dfs start 排列 bool

原题链接:https://www.luogu.com.cn/problem/P1088

题意解读:

火星人的手指可以通过全排列来表示数字,全排列由小到大的顺序即为表示的数字大小,题目可以转化为:

给定按顺序全排列中的某一个排列,求往后数m个排列的内容。

解题思路:

此题与经典全排列问题的差异在于,需要从指定一个排列开始,往后找m个排列。注意由于n值多达10000,如果从头开始全排列,找到指定排列开始,很可能超时,因为全排列时间复杂度是O(n!)。

要从指定排列开始,只需要在经典全排列代码中,加入标记判断,如果还未找到指定起始排列,则赋值为制定排列中的数值,然后继续dfs。

30分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int n, m;
int a[N], t[N];
bool flag[N];

bool start; //判断是否已找到起始排列
int cnt; //从起始排列开始计数

void dfs(int k)
{
    if(k > n) //找到一组排列
    {
        if(!start) start = true; //找到的是起始排列,说明可以开始计数了
        else
        {
            if(++cnt == m) //计数,如果是往后数m个排列,输出结果
            {
                for(int i = 1; i <= n; i++) cout << t[i] << " ";
                cout << endl;
            }
        }
        return;
    }
    for(int i = 1; i <= n; i++)
    {
        if(!start) //如果还没有找到起始排列
        {
            i = a[k]; //i从指定的排列数a[k]开始
        }
       
        if(!flag[i])
        {
            flag[i] = true;
            t[k] = i;
            dfs(k + 1);
            flag[i] = false;
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    dfs(1);
    return 0;
}

此代码的问题在于,当找到第m个排列之后,函数没有及时终止,dfs要终止,直接return不行,因为只return了本层递归,上层递归和枚举还在继续,

需要在dfs中return一个标识,true表示已结束,false表示未结束,在所有调用dfs的地方,增加对返回值的判断并进一步return true/false,这样才能在

找到结果后层层返回,起到及时终止程序的作用。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 10005;

int n, m;
int a[N], t[N];
bool flag[N];

bool start; //判断是否已找到起始排列
int cnt; //从起始排列开始计数

bool dfs(int k)
{
    if(k > n) //找到一组排列
    {
        if(!start) start = true; //找到的是起始排列,说明可以开始计数了
        else
        {
            if(++cnt == m) //计数,如果是往后数m个排列,输出结果
            {
                for(int i = 1; i <= n; i++) cout << t[i] << " ";
                cout << endl;
                return true; //已经找到,直接返回true,后续不用再继续递归了
            }
        }
        return false;
    }
    for(int i = 1; i <= n; i++)
    {
        if(!start) //如果还没有找到起始排列
        {
            i = a[k]; //i从指定的排列数a[k]开始
        }
       
        if(!flag[i])
        {
            flag[i] = true;
            t[k] = i;
            bool res = dfs(k + 1);
            if(res) return true; //如果已经找到第m个数,不用继续dfs处理了,以免超时
            flag[i] = false;
        }
    }

    return false;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    dfs(1);
    return 0;
}

 

标签:NOIP2004,火星人,return,int,洛谷题,dfs,start,排列,bool
From: https://www.cnblogs.com/jcwy/p/17999598

相关文章

  • 洛谷题单指南-暴力枚举-P1706 全排列问题
    原题链接:https://www.luogu.com.cn/problem/P1706题意解读:n个数全排列问题,本质上,给定n个空位,枚举每个能填入空位的数,依次填入,每个数只能填一次。解题思路:如何填入n个数呢,可以借助于递归,流程如下:dfs(填入第k个数){如果已经填满n个数输出结果返回......
  • 洛谷题单指南-暴力枚举-P1157 组合的输出
    原题链接:https://www.luogu.com.cn/problem/P1157题意解读:在1~n的数中挑选r个,有多少种组合,与P1036类似,有两种做法:二进制法、DFS,下面给出DFS版的代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;constintN=25;intn,r;intt[N];voiddfs(intk){......
  • 洛谷题单指南-暴力枚举-P1036 [NOIP2002 普及组] 选数
    原题链接:https://www.luogu.com.cn/problem/P1036题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。解题思路:方法一:二进制法通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。......
  • 洛谷题单指南-暴力枚举-P1618 三连击(升级版)
    原题链接:https://www.luogu.com.cn/problem/P1618题意解读:枚举所有三位数的组合情况,判断是否符合比例。解题思路:方法一:枚举第一个数根据题意,目的是寻找三个符合比例的三位数,可以直接枚举第一个,最小是123,最大是987设第一个数为x,三个数的比例关系是a:b:c设另外两个数为y,z那么,根......
  • 洛谷题单指南-暴力枚举-P2241 统计方形(数据加强版)
    原题链接:https://www.luogu.com.cn/problem/P2241题意解读:要在整个n*m区域计算正方形和长方形的个数,枚举法即可。解题思路:此题枚举的对象是矩形的高i和宽j,高的范围[1,n],宽的范围[1,m],然后计算在n*m区域内有多少个i*j,i==j即属于正方形,i!=j属于长方形。那么,问题就集中在了......
  • 洛谷题单指南-排序-P1012 [NOIP1998 提高组] 拼数
    原题链接:https://www.luogu.com.cn/problem/P1012题意解读:通过某种合理的排序方式,使得排序后的数字连在一起最大。解题思路:此题关键在于排序,对于两个数字,哪个数字应该排在前面呢?1、思考误区很容易想到,给定两个数abcd、xyz,先比较第一位a和x,谁大谁排前面,一直到c和z。再来看d,这......
  • 洛谷题单指南-排序-P1104 生日
    原题链接:https://www.luogu.com.cn/problem/P1104题意解读:将学生按照年龄由大到小排序,如果年龄相同,后输入的排在前面,输出排序后的学生姓名。解题思路:此题是一个排序常规题,年龄大排在前说明年、月、日越小越在前面,核心的排序思路如下:1、如果年份不同,按年份由小到大排序2、如果......
  • 洛谷题单指南-排序-P5143 攀爬者
    原题链接:https://www.luogu.com.cn/problem/P5143题意解读:给出一系列的点,按某种顺序经过所有点,计算距离。解题思路:如果小学生,可能对于三维坐标距离有些陌生,没关系,题目已经给出了计算公式,直接套公式即可,关键步骤如下:1、读取所有坐标点2、按高度值从小到大排序3、从头依次计算......
  • 洛谷题单指南-排序-P1068 [NOIP2009 普及组] 分数线划定
    原题链接:https://www.luogu.com.cn/problem/P1068题意解读:根据题意,用模拟法,求出分数线所在位置,然后计算分数线,最后输出结果即可。解题思路:1、分数线是按从大到小排名来设定,因此数据因为按照分数从大到小排序,如果分数相同,需要安装报名号从小到大排序2、计算分数线位置,主要是下......
  • 洛谷题单指南-排序-P1152 欢乐的跳
    原题链接:https://www.luogu.com.cn/problem/P1152题意解读:要判断相邻数差的绝对值是否覆盖1~n-1,只需遍历相邻两数之差,借助数组标记差的绝对值是否存在,然后遍历数组即可。解题思路:此题有两个注意点:1、数值要用longlong2、计算差值绝对值后,标记桶数组时,有可能导致越界,因为每个......