过了半年多了,身为一名acmer,连搜索都不会,实属是罪过啊,最近遇到得dfs题太多了,要是不会岂不是脸憋得发红。。。写一些dfs得入门题加深一下
文章目录
1.dfs入门经典题:全排列 传送门
题目描述
给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
输入格式
共一行,包含一个整数n。
输出格式
按字典序输出所有排列方案,每个方案占一行。
数据范围
1≤n≤7
样例输入
3
样例输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
解题思路:此题也能用c++库函数解决(next_permutation),数据较强的话会被TLE,数据很小,于是能枚举出任何情况,有些解释见代码吧
AC源:
#include<iostream>
using namespace std;
const int N = 10 ;
int a[N]; ///存储答案
bool vis[N]; ///用于标记哪些数可以选
int n;
void dfs(int k){
if(k==n){ ///搜索到一种答案并输出
for(int i=0;i<n;i++) cout << a[i] << " ";
cout << endl;
return ;
}
for(int i=1;i<=n;i++)
{
if(!vis[i]) ///表示该数可以选
{
a[k]=i; ///进入答案数组
vis[i]=true; ///标记
dfs(k+1); ///搜索下一层
vis[i]=false; ///现场还原---回溯
}
}
}
int main(){
scanf("%d",&n);
dfs(0); ///从第0层搜索
}
2.组合输出 传送门
题目描述
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r<=n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
例如n=5,r=3,所有组合为:
l 2 3 l 2 4 1 2 5 l 3 4 l 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
输入
一行两个自然数n、r(1<n<21,1<=r<=n)。
输出
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。(每一个数后跟一个空格)
样例输入
5 3
样例输出
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
解题思路:和上题一样也能用c++库函数完成,数据较强时也会被TLE,这题得思路和上题差不多,只是循环的边界不同
AC源:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int n,m;
int a[30];
bool vis[30];
void dfs(int k){
if(k==m){
for(int i=0;i<m;i++)
{
///if(i==0) cout << a[i];
cout << a[i] << " ";
}
cout << endl;
return ;
}
for(int i=a[k-1];i<n;i++) ///与上题的不同之处
{
if(!vis[i])
{
vis[i]=true;
a[k]=i+1;
dfs(k+1);
vis[i]=false;
}
}
}
int main(){
scanf("%d%d",&n,&m);
dfs(0);
}
3.2020春季个人训练赛 4.25日场 分书问题
时间限制: 1 Sec 内存限制: 128 MB
题目描述
已知有n本书(从1~n编号)和n个人(从1~n编号),每个人都有一个自己喜爱的书的列表,现在请你编写一个程序,设计一种分书方案,使得每个人都能获得一本书,且这本书一定要在他的喜爱列表中。
输入
输入数据共若干行,第一行为一个正整数n(n <= 20),从第2行到第n+1行,每行有n个0或1组成,第k行表示编号为k-1的人对这n本书的喜好列表,0表示不喜欢,1表示喜欢。
输出
输入数据共若干行,第一行为一个正整数n(n <= 20),从第2行到第n+1行,每行有n个0或1组成,第k行表示编号为k-1的人对这n本书的喜好列表,0表示不喜欢,1表示喜欢。
样例输入
5
00110
11001
01100
00010
01001
样例输出
1
解题思路:这是比较基础的dfs了,我的思路就是以行为单位,每次搜索一行,别的也没啥,看代码吧
AC源:
#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
typedef pair<ll,ll> PII;
map<string,int>mp;
int a[100][100],vis[100][100];
int n,ans=0;
void dfs(int k){
if(k==n+1){ ///搜索结束条件,搜到n+1行
ans++;
return ;
}
for(int i=1;i<=n;i++)
{
if(a[k][i]==1&&vis[k][i]==1) ///该书是喜欢的书并且该书可以选
{
for(int j=k;j<=n;j++) vis[j][i]=0; ///如果第k行的这本书被选了,k+1--n行的这本书都不能选了,置为0
dfs(k+1);
for(int j=k;j<=n;j++) vis[j][i]=1; ///现场还原
}
}
}
int main(){
string s[100];
scanf("%d",&n);
for(int i=1;i<=n;i++) cin >> s[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) a[i][j]=s[i][j-1]-'0',vis[i][j]=a[i][j]; ///vis数组是用来记录该书可不可以选的
}
dfs(1); ///从第一行开始搜
cout << ans;
return 0;
}