目录
深度优先搜索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;
}