【DFS入门题小集】

过了半年多了,身为一名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;
}

猜你喜欢

转载自blog.csdn.net/zhazhaxiaosong/article/details/105850814
今日推荐