深度优先搜索DFS搜索数及B3621 枚举元组 B3622 枚举子集 B3623 枚举排列

目录

深度优先搜索DFS搜索

B3621 枚举元组

题面

题解

代码

B3622 枚举子集

题面

题解

代码

B3623 枚举排列

题面

题解

代码


深度优先搜索DFS搜索

DFS:从根节点出发,寻找子节点,到最深层返回到上一层继续递归搜索。

B3621 枚举元组

题目传送

题面

题目描述

n 元组是指由 n 个元素组成的序列。例如 (1,1,2) 是一个三元组、(233,254,277,123)是一个四元组。

给定 n 和 k,请按字典序输出全体 n 元组,其中元组内的元素是在 [1,k] 之间的整数。

「字典序」是指:优先按照第一个元素从小到大的顺序,若第一个元素相同,则按第二个元素从小到大……依此类推。详情参考样例数据。

输入格式

仅一行,两个正整数 n,k。

输出格式

若干行,每行表示一个元组。元组内的元素用空格隔开。

输入输出样例

输入 #1 

2 3

输出 #1 

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3

题解

排列组合类题目,此时使用dfs递归搜索出“最深层”的数据,当搜索到一个pos的最深层,输出这一次所有数。此时的i是从1开始搜索,默认第一个从1开始,dfs搜索中数组答案a的pos位置为i,继续递归下一个pos+1的位置,知道搜索到终点。dfs循环中pos到达终点必须写return;否则会出现死循环。

代码

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

int a[100005]; 
int n,k;
void dfs(int pos){
    if(pos==n+1){//递归到终点了,n个位置都确定了
        for(int i=1;i<=n;i++)
            cout<<a[i]<<" "; 
        cout<<endl;
        return;
    }
    for(int i=1;i<=k;i++){
        a[pos] = i; //第pos个位置为i
        dfs(pos+1); //递归下一个位置
    }
}
int main(){
     
    cin>>n>>k;
    dfs(1); //从第1个位置开始搜索
}

B3622 枚举子集

题目传送

题面

题目描述

今有 n 位同学,可以从中选出任意名同学参加合唱。

请输出所有可能的选择方案。

输入格式

仅一行,一个正整数 n。

输出格式

若干行,每行表示一个选择方案。

每一种选择方案用一个字符串表示,其中第 i 位为 Y 则表示第 i 名同学参加合唱;为 N 则表示不参加。

需要以字典序输出答案。

输入输出样例

输入 #1 

3

输出 #1 

NNN
NNY
NYN
NYY
YNN
YNY
YYN
YYY

题解

题目中的Y和N可以看作布尔数组,方便理解,和编写代码。如果是N,那么负值为0,如果是Y那么负值就是非0的数(1)。每一种组合的每一个数必须是N或Y,所以所有的数都可以用0或1代替。思路和上一道题目一样,dfs的搜索是从所有可能的数字选择下一个后递归填充此时pos位置的数值i。如果pos=n+1(到了一个数列长度极限),判断+输出。这里的dfs循环也需要return;代码否则会出现死循环。

要点:

  • dfs() 表示枚挙到第i个人。
  • a数组保存当前枚举情况,a们来存第i个人参加,还是不参加。
  • 当枚举完所有的人,就全部输出。
  • dfs(pos) 負責枚挙 alpos」。

代码

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

int n, k;
int a[15];

void dfs(int pos) {
    if(pos==n+1) { // 枚举完所有人
        for(int i=1;i<=n;i++){ // 输出方案
            if(a[i]==0)cout<<"N";// 如果是 0 输出 'N'
            else cout<<"Y";// 否则输出 'Y'
        }
        cout << endl;
        return;
    }

    for(int i=0;i<=1;i++) {
        a[pos] = i;    // 将 pos 位填充成 i
        dfs(pos+1);    // 递归填写后续位置
    }
}

int main() {
    cin >> n;

    dfs(1); // 最先枚举第几个人?

    return 0;
}

B3623 枚举排列

题面

题目描述

今有 n 名学生,要从中选出 k 人排成一列拍照。

请按字典序输出所有可能的排列方式。

输入格式

仅一行,两个正整数 n,k。

输出格式

若干行,每行 k 个正整数,表示一种可能的队伍顺序。

输入输出样例

输入 #1

3 2

输出 #1

1 2
1 3
2 1
2 3
3 1
3 2

题解

思路和前两道题相同,输出这个排列的方式的同时还要确保没有重复的数字,所以加一判断就可以。我们还需要一个数组use定义一个数是否被用过,那么下一个递归的数就不可能是用过的了。其他dfs的思路一样。

要点:

dfs(i) 表示枚举到第i个人。

a 数组保存当前枚举情况,a[i] 来存第i个人是谁

只有use[i] =0 时可以使用i

在填充i后将use[i] 设为1,然后继续枚举下一个

递归回来后,将use[i] 还原

代码

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

int n, k;
int a[1000], use[10000];

void dfs(int pos) {
    if(pos == k+1) {
        for(int i = 1; i <= k; i++)
            cout << a[i] << ' ';
        cout << endl;

        return;
    }

    for(int i = 1; i <= n; i++)
        if(!use[i]) { // 如果第 i 个元素没有被使用
            use[i] = 1; // 将其标记为被使用
            a[pos] = i; // 更新 a[pos]
            dfs(pos+1); // 枚举下一个
            use[i] = 0; // 将其标记为未被使用
        }
}

int main() {
    cin >> n >> k;

    dfs(1);

    return 0;
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值