第三章 搜索与图论(一)

本文简介:深度优先搜索、广度优先搜索、树和图的DFS和BFS、拓扑排序。

一、深度优先搜索DFS

 深度优先搜索的思路可以看作,先遍历完找到满足条件的情况,然后再回溯寻找别的满足条件的情况。

acwing845

#include<iostream>
using namespace std;
const int N = 10;
//path[i]代表第i层遍历,st[i]标志第i的点已经被遍历过了
int path[N],n;
bool st[N];

void dfs(int u){
    if(u==n){
        for(int i = 0;i<n;i++) printf("%d ",path[i]);
        puts(" ");
    }
    for(int i = 1;i <= n;i++){
        if(!st[i]){
            path[u] = i;
            st[i] = true;//标记
            dfs(u + 1);//递归
            st[i] = false;//回溯
        }
    }
    
}


int main(){
    scanf("%d",&n);
    dfs(0);
    return 0;
}

acwing-843 N皇后问题

 #include<iostream>
 using namespace std;
 
const int N = 20;
int n;
char g[N][N];
bool col[N],dg[N],udg[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[2*n-u-i] && !udg[n-u+i]){
            g[i][n-u-1] = 'Q';
            col[i] = dg[2*n-u-i] = udg[n-u+i] = true;
            dfs(u+1);
            col[i] = dg[2*n-u-i] = udg[n-u+i] = false;
            g[i][n-u-1] = '.';
        }
    }
    
    
}


int main(){
    scanf("%d",&n);
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++){
            g[i][j] = '.';
        }
    }
    dfs(0);
    return 0;
    
}

二、宽度优先搜索BFS

acwing 844 走迷宫

有点问题的做法,等待日后修正

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

int n, m;
int maze[N][N];
bool p[N][N];
int re = 10000;
void dfs(int x, int y, int tmp) {
    
    if (x == n && y == m) {
        if (tmp < re) {
            re = tmp;
            cout << "有一个解为:"<< re << endl;
        }

    }
    if (!maze[x + 1][y] && !p[x + 1][y] && x+1<=n) {
        p[x + 1][y] = true;
        cout << x + 1 << " " << y << endl;
        dfs(x + 1, y, tmp + 1);
        cout << "此方案不可行截止" << endl;
        p[x + 1][y] = false;
        
    }
    if (!maze[x][y + 1] && !p[x][y + 1] && y+1<=m) {
        p[x][y + 1] = true;
        cout << x << " " << y + 1 << endl;
        dfs(x, y + 1, tmp + 1);
        cout << "此方案不可行截止" << endl;
        p[x][y + 1] = false;
    }
    if ((x - 1)>0 && !maze[x - 1][y] && !p[x - 1][y] && !(x-1)==y==1) {
        p[x - 1][y] = true;
        cout << x - 1 << " " << y << endl;
        dfs(x - 1, y, tmp + 1);
        cout << "此方案不可行截止" << endl;
        p[x - 1][y] = false;
    }
    if ((y - 1)>0 && !maze[x][y - 1] && !p[x][y - 1] && !x==(y-1)==1) {
        p[x][y - 1] = true;
        cout << x << " " << y - 1 << endl;
        dfs(x, y - 1, tmp + 1);
        cout << "此方案不可行截止" << endl;
        p[x][y - 1] = false;
    }
}


int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin>>maze[i][j];
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cout << maze[i][j];
        }
        cout << endl;
    }
    p[1][1] = true;
    dfs(1, 1, 0);
    printf("%d", re);
    return 0;
}

正确的

宽度优先搜索框架:

#include<iostream>
#include<cstring>
#include<queue>
#define _CRT_SECURE_NO_WARNINGS 1
using namespace std;
const int N = 110;
typedef pair<int, int> PII;


int n, m;
int mark[N][N], map[N][N];//mark用作还没有走过该节点,也可以表示到此节点共走了多少步,map是存储的迷宫
int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };

void bfs() {
    queue<PII> q;
    mark[0][0] = 0;
    q.push({ 0,0 });
    while (!q.empty()) {
        PII tmp = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int nex = tmp.first + dx[i], ney = tmp.second + dy[i];
            if (nex >= 0 && nex < n && ney >= 0 && ney < m && mark[nex][ney] == -1 && map[nex][ney] == 0) {
                mark[nex][ney] = mark[tmp.first][tmp.second] + 1;
                q.push({ nex,ney });
            }
        }
    }
    cout << mark[n - 1][m - 1];

}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &map[i][j]);
        }
    }
    memset(mark, -1, sizeof(mark));
    bfs();
}

三、树和图的存储

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100010,M = N * 2;
int n;
int h[N],e[M],ne[M],idx,ans = N;
bool st[N];
void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

//找到将u节点删除后,剩余各个连通块中点数最大的值。
int dfs(int u){
    st[u] = true;

    int size = 0, sum = 0;
    for (int i = h[u]; i != -1; 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(){
    scanf("%d",&n);
    memset(h,-1,sizeof h);
    for(int i = 0;i < n-1;i++){
        int a,b;
        scanf("%d%d", &a, &b);
        add(a,b),add(b,a);
    }
    dfs(1);
    printf("%d\n", ans);
}

四、树和图的遍历

五、拓扑排序

acwing 848

 题中的关键是若一个由图中所有点构成的序列 A满足:对于图中的每条边 (x,y),x在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。则拓扑序列一定满足没有环,且没有环的一定满足是一个拓扑序列。

没有环则可以推出至少有一个入度为0的点

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

const int N = 100010;

int n,m;
int h[N],e[N],ne[N],idx;
int d[N],q[N];

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++){
        if(!d[i]){
            q[ ++tt ] = i;
        }
    }
    while(hh <= tt){
        int t = q[hh++];
        
        for(int i = h[t];i != -1;i = ne[i]){
            int j = e[i];
            if( -- d[j] == 0) q[++tt] = j;
        }
    }
    
    return tt == n-1;
}

int main(){
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i = 0;i<m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        d[b]++;
    }
    if(!topsort()) puts("-1");
    else{
        for(int i = 0;i<n;i++) printf("%d ",q[i]);
    }
    return 0;
    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值