搜索

总结:搜索这一块dfs思路很好懂,但是有时从题目中抽象出来很难,bfs相对简单。


        空间        时间        数据结构
DFS :  O(n)      O(n + m)      stack          不具有最短性
BFS :  O(2^h)    O(n + m)      queue          具有最短性


DFS

>排列数字

每层选一个未选过的数字,选n层后输出方案。

回溯时:确定没有一条路能走时才会回溯

#include<iostream>
using namespace std;


const int N = 10;
int path[N];
bool st[N];
int n;
void dfs(int u)
{
    if(u == n)
    {
        for(int i = 0;i < n;i++)
        {
            printf("%d ",path[i]);
        }
        puts("");
        return ;
    }
    
    for(int i = 1;i <= n;i++)
    {
        if(!st[i])
        {
            path[u] = i;
            st[i] = true;
            dfs(u+1);
            st[i] = false;
        }
    }
}

int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

全排列stl--next_permutation

例:输出1到4的全排列

#include <iostream>
#include<algorithm>
using namespace std;
 
int main(int argc, char** argv) {
	int a[4]={1,2,3,4};
	sort(a,a+4);
	do{
		for(int i=0;i<4;i++)
		    cout<<a[i]<<" ";
		cout<<endl;
	}while(next_permutation(a,a+4));
	return 0;
}


>n皇后问题

法一:每一层选一个,其条件是正反对角线和当前列不能有元素(剪枝) 法二:从(0,0)开始选,每个点选或不选,同样剪枝。

恢复状态:上个状态什么样,就得恢复成什么样
法一

#include<iostream>
using namespace std;

const int N = 15;

int n;
char g[N][N];
bool col[N],dg[2 * N],udg[2 * N];//列,对角线,反对角线

void dfs(int u)
{
    if(u == n)
    {
        for(int i = 0;i < n;i++) puts(g[i]);
        puts("");
        return ;
    }

    for(int i = 0;i < n;i++)
    {
        if(!col[i] && !dg[u + i] && !udg[n - u + i])
        {
            g[u][i] = 'Q';
            col[i] = dg[i+u] = udg[n - u + i] = true;
            dfs(u+1);
            col[i] = dg[i+u] = udg[n - u + i] = false;
            g[u][i] = '.';
        }
    }
}
int main()
{
    cin>>n;
    for(int i = 0;i < n;i++)
     for(int j = 0;j < n;j++)
      g[i][j] = '.';

    dfs(0);
    return 0;
}

法二

#include <iostream>
using namespace std;
const int N = 20;

int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N];

// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
    // 处理超出边界的情况
    if (y == n) y = 0, x ++ ;

    if (x == n) { // x==n说明已经枚举完n^2个位置了
        if (s == n) { // s==n说明成功放上去了n个皇后
            for (int i = 0; i < n; i ++ ) puts(g[i]);
            puts("");
        }
        return;
    }

    // 分支1:放皇后
    if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
        g[x][y] = 'Q';
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
        dfs(x, y + 1, s + 1);
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
        g[x][y] = '.';
    }
    //分支2:不放皇后
    dfs(x,y+1,s);
}    


int main(){
    cin>>n;
    for(int i=0;i<n;i++)
     for(int j=0;j<n;j++)
      g[i][j]='.';

    dfs(0,0,0);
    return 0;
}


BFS

走迷宫

从队头开始扩展相邻的状态,每层更新一次距离,得出答案。

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

typedef pair<int,int> PII;
const int N = 110;
int n,m;
int g[N][N],d[N][N];
PII q[N * N];

int bfs()
{
    memset(d,-1,sizeof d);
    int hh=0,tt = -1;
    d[0][0] = 0;
    q[++tt] = {0,0};
    
    int dx[] = {-1,1,0,0},dy[] = {0,0,-1,1};
    
    while(hh <= tt)
    {
        PII t = q[hh++];
        
        
        for(int i = 0;i < 4;i++)
        {
            int x = t.first + dx[i],y = t.second + dy[i];
            if(x >= 0 && x < n && y >= 0 && y < m && d[x][y] == -1 && g[x][y] == 0)
            {
                d[x][y] = d[t.first][t.second] + 1;
                q[++tt] = {x,y};
            }
        }
    }
    return d[n-1][m-1];
    
}

int main()
{
    cin>>n>>m;
    for(int i = 0;i < n ;i++)
     for(int j = 0;j < m;j++)
      cin>>g[i][j];
      
    cout<<bfs()<<endl;
    return 0;
}

\(边权为1时,bfs处理最短路。\)


树与图的DFS

>树的重心

遍历每个点,找出具有最大结点数的子树s,s的结点数和n-总结点数作比较,遍历每个点时都能找到其比较后的最大值,最后找到这些最小的最大值。

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

const int N = 1e5 + 10;

int e[N * 2],h[N],ne[N * 2],idx;
int n;

int res;
int ans = N;
bool st[N];
void add(int a,int b)//头插
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
    
}

int dfs(int u)//返回子树的结点数
{ 
    st[u] = true;
    
    int size = 0,sum = 0;//结点总数
    for(int i = h[u] ; ~i;i = ne[i])
    {
        int j = e[i];
        if(st[j]) continue;
        
        int s = dfs(j);
        size = max(size,s);//子树最多有多少个结点
        sum += s;
    }
    size = max(size ,n - sum - 1);
    
    ans = min(ans,size);
    
    return sum + 1;
}

int main()
{
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i = 0; i < n;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs(1);
    cout<<ans<<endl;
    return 0;
}


树与图的BFS

>图中点的层次

从1号点开始不断扩展,每次扩展到的点距离加1,直到n点被扩展到。

#include<iostream>
#include<cstring>

using namespace std;

const int N = 1e5 + 10;
int h[N],ne[N * 2],e[N * 2],idx;

int n,m;
int d[N],q[N];
void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int bfs()
{
    int hh = 0,tt = -1;
    memset(d,-1,sizeof d);
    d[1] = 0;
    q[++tt] = 1;
    
    while(hh <= tt)
    {
        int t = q[hh++];
        for(int i = h[t];~i;i = ne[i])
        {
            int j = e[i];
            if(d[j] == -1)//未被遍历过
            {
                 d[j] = d[t] + 1;
                 q[++tt] = j;
            }
        }
    }
    return d[n];
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i = 0;i < m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    
    cout<<bfs()<<endl;
    return 0;
}


>有向图的拓扑序列

有向无环图一定具有拓扑序,入度为0的点作起点。

#include<iostream>
#include<cstring>

using namespace std;

const int N = 1e5 + 10,M = 2e5 + 10;
int n,m;
int d[N],q[N];

int e[M],ne[M],h[N],idx;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

bool Topsort()
{
    int hh = 0,tt = -1;
    for(int i = 1;i <=n;i++)//所有入度为0的点入队
     if(d[i] == 0)
         q[++tt] = i;
     
     
    while(hh <= tt)
    {
        int t = q[hh++];
        for(int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            d[j]--;
            if(d[j] == 0) q[++tt] = j;
        }
    }
    
    return tt == n - 1;
}


int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i = 0;i < m;i++)
    {
        int  a,b;
        cin>>a>>b;
        d[b]++;
        add(a,b);
    }
    
    if(Topsort())
    {
        for(int i = 0;i < n;i++) cout<<q[i]<<' ';
    }else {
        cout<<"-1"<<endl;
    }
    
    return 0;
}
上一篇:Spring Cloud + Spring Boot + Mybatis + Uniapp 企业架构之CAS SSO单点登录客户端环境搭建


下一篇:寒假笔记本5:氰及其化合物