DFS/BFS

关于DFS其实本质就是,当path达到对应数量就输出!如果没有达到,那么看看哪些还可以选择,如果可以选择就插入path,标记不可选,然后递归,然后标记可用,然后弹出,就是这么一个套路。
DFS:达则可,否则遍历入标递标出。
BFS:队列不空出遍入。

排列数字

使用回溯法生成所有可能的排列
每次选择一个未使用过的数字加入当前排列
当排列长度达到 n 时,输出该排列
通过按顺序尝试数字,自然保证了字典序

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int n;
vector<bool> used; 
vector<int> path;

void work(){
    if(path.size()==n){//如果path中达到对应数目
        for (int i = 0; i < n; i ++ ){
            cout << path[i] << " ";
        }
        cout << endl;
        return;
    }
    for (int i = 1; i <= n; i ++ ){//循环每一个第一个数字,然后加入path然后递归
        if(used[i]==false){
            path.push_back(i);
            used[i]=true;
            work();
            used[i]=false;
            path.pop_back();
        }
    }
}

int main()
{
    cin >> n;
    used.resize(n+1,false);
    work();
    return 0;
}

n皇后问题

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;
int n;
vector<int> path;//候选
vector<bool> y;//列可用
vector<bool> ipj;//i+j对角线
vector<bool> idj;//i-j对角线

void printq(int a){
    for (int i = 1; i < a; i ++ ){
        cout << ".";
    }
    cout << "Q";
    for (int i = 1; i <= n-a; i ++ ){
        cout << ".";
    }
    cout <<endl;
}
//标准格式,如果达到长度循环打印,返回
//然后就是遍历,如果符合条件加入并且标记,递归,结束则删除去除标记
void work(){
    int i = path.size()+1;
    if(path.size()==n){
        for (int i = 0; i < n; i ++ ){
            printq(path[i]);
        }
        cout << endl;
        return;
    }//每一行,选取哪个?
    for(int j = 1; j <= n;j++){
        if(y[j]&&ipj[i+j]&&idj[i-j+n]){//判断对应的可以使用,注意i-j可能是负数要+n转化
            path.push_back(j);
            y[j] = false;
            ipj[i+j] = false;
            idj[i-j+n] = false;
            work();
            //标记为true
            y[j] = true;
            ipj[i+j] = true;
            idj[i-j+n] = true;                
            path.pop_back();
        }
    }
}

int main()
{
    cin >> n;
    y.resize(n+1,true);
    ipj.resize(2*n+2,true);
    idj.resize(2*n+2,true);//因为+n了这里的也要稍微改一下
    work();
    return 0;
}

走迷宫

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
int n,m;
int A[100][100];
int dist[100][100];//到达目的地的距离
queue<pair<int,int>> pos;//使用队列是因为遍历的是之前的而不是走到底才往回走
int x,y,a,b;

int dx[4]={0,1,0,-1};
int dy[4]={-1,0,1,0};

int main()
{
    cin >> n>>m;
    for (int i = 0; i < n; i ++ ){
        for (int j = 0; j < m; j ++ ){
            cin >> A[i][j];
        }
    }
    for (int i = 0; i < n; i ++ ){
        for (int j = 0; j< m; j ++ ){
            dist[i][j] = -1;
        }
    }
    dist[0][0] = 0;
    pos.push({0,0});
    while(!pos.empty()){
        x = pos.front().first;
        y=  pos.front().second;
        pos.pop();
        if(dist[n-1][m-1]!=-1){
            cout <<dist[n-1][m-1];return 0;
        }
        for (int i = 0; i < 4; i ++ ){
            a = x+dx[i]; b = y + dy[i];
            if(a>=0&&a<n&&b>=0&&b<m&&A[a][b]==0&&dist[a][b]==-1){//重点四个判断,ab符合条件,A是可走,dist未曾记录
                dist[a][b] = dist[x][y]+1;
                pos.push({a,b});
            }
        }
    }
    return 0;
}

华容道

BFS的思路就是使用一个队列,先初始化第一个,然后对第一个进行各种操作,如果符合正常条件就加入队列,循环各种,然后每次取头,如果这个头代表的符合要求就直接输出结果。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>

using namespace std;

unordered_map<string,int> mi;
queue<int> idx;
char M[332000][10];
int now;
int nowx;
int cx[4] = {-1,0,1,0};
int cy[4] = {0,1,0,-1};
int cou=1;
int a,b;
int dist=1;
int getx(){
    for (int i = 0; i < 9; i ++ ){
        if(M[now][i]=='x')return i;
    }
}

int check(){
    for (int i = 0; i < 10; i ++ ){
        M[cou][i] = M[now][i];
    }
    swap(M[cou][nowx],M[cou][a*3+b]);
    if(mi.find(string(M[cou]))!=mi.end())return 0;
    else return 1;
}

int main()
{
    for (int i = 0; i < 9; i ++ ){
        cin>>M[0][i];
    }
    M[0][9]='\0';
    mi[string(M[0])] = 0;
    idx.push(0);
    while(!idx.empty()){
        now = idx.front();//
        idx.pop();
        nowx = getx();
        if(string(M[now])=="12345678x"){cout << mi[string(M[now])];return 0;}
        //cout << string(M[now])<<endl;
        for (int i = 0; i < 4; i ++ ){
            a = nowx/3+cx[i];
            b = nowx%3+cy[i];//新的横纵
            if(a>=0&&a<3&&b>=0&&b<3&&check()){
                mi[string(M[cou])] = mi[string(M[now])]+1;
                idx.push(cou);
                cou++;
            }
        }
    }
    cout << -1;
    return 0;
}

树的重心

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;
vector<vector<int>> edge;
vector<int> sizee;
int min_max_subtree=100100;

int n;

void work(int son, int fat){
    sizee[son] = 1;
    int max_subtree = 0;
    for(int x:edge[son]){
        if(x==fat)continue;
        work(x,son);//遍历每个边都递归,记录size,并且筛选最大的连通
        sizee[son] += sizee[x];
        max_subtree = max(max_subtree,sizee[x]);//针对当前循环下的子树
    }
    max_subtree = max(max_subtree, n - sizee[son]);//针对当前函数的子数,与父方向的比较
    min_max_subtree = min(min_max_subtree,max_subtree);//找到最小的联通
}

int main()
{
    int a,b;
    cin >> n;
    edge.resize(n+1);
    sizee.resize(n+1);
    for (int i = 0; i < n-1; i ++ ){
        cin >> a >> b;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }
    work(1,-1);//从1开始其实从哪里开始都一样
    cout << min_max_subtree;
    return 0;
}

图中点的层次

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;
int n,m;
vector<vector<int>> edge;
int a,b;
vector<int> dist;
queue<int> path;
int now;
vector<int> res;
vector<int> visit;

int main()
{
    cin >> n >> m;
    edge.resize(n+1);
    dist.resize(n+1);
    visit.resize(n+1);
    for (int i = 0; i <= n; i ++ ){
        dist[i]=0;
        visit[i]=0;//初始化
    }
    for (int i = 0; i < m; i ++ ){
        cin >> a >> b;
        edge[a].push_back(b);
    }
    path.push(1);
    while(!path.empty()){
        if(dist[n]){
            res.push_back(dist[n]);//如果有到n的就加入结果
            dist[n]=0;
        }
        now = path.front();
        path.pop();
        for(int x:edge[now]){
            if(x==now||visit[x])continue;
            path.push(x);//遍历每一个,加入结果并且记录距离
            dist[x] = dist[now]+1;
            visit[x]=1;
        }        
    }
    if(n==1){cout<<0;return 0;}//如果n=1直接就是0
    if(res.size()){//多个结果找最小
        int r=res[0];
        for(int x:res){
            r = min(r,x);
        }
        cout << r;
        return 0;
    }
    cout << -1;//都没有输出-1
    return 0;
}

拓扑排序

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
vector<vector<int>> edge;
//vector<vector<int>> inme;//使用入度数组,而不是进入的元素数组!
int n,m,a,b;
queue<int> path;
vector<int> res;
//还是BFS
int main()
{
    cin >> n >> m;
    edge.resize(n+1);
    vector<int> indu(n+1,0);
    //for (int i = 1; i <= n; i ++ ){
    //    visit[i]=0;
    //}
    for (int i = 0; i < m; i ++ ){
        cin >> a >> b;
        edge[a].push_back(b);
        indu[b]++;
    }
    int head=-1;
    for (int i = 1; i <= n; i ++ ){
        if(!indu[i]){
            path.push(i);
        }
    }
    while(!path.empty()){
        int now = path.front();
        path.pop();
        res.push_back(now);      
        
        for(int x:edge[now]){//还得考虑入度为0的情况,而不是都加入
            indu[x]--;//抹除我的进入
            if(now==x||indu[x])continue;
            path.push(x);
        }
    }
    if(res.size()==n){//处理不存在序列的情况,如果存在那么会达到n长
        for(int x:res)cout << x << " ";
    }
    else{
        cout << -1;
    }
    return 0;
}
posted @ 2025-08-04 10:02  .N1nEmAn  阅读(7)  评论(0)    收藏  举报