基本算法DFS以及BFS

图的深搜

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 100;

int G[maxn][maxn], vis[maxn];
int n, m;
vector<int> ans;

void dfs(int start) {
    vis[start] = 1;
    ans.push_back(start);

    for(int i = 0; i < n; i++)
        if(!vis[i] && G[start][i])  dfs(i);
}

int main()
{
    printf("please enter the number of  nodes and sides:\n");
    scanf("%d", &n);    scanf("%d", &m);

    int u, v, val;      memset(G, 0, sizeof(G));        //首先要清空临接矩阵
    printf("crate the matrix:\n");
    for(int i = 0; i < m; i++) {        //建立临接矩阵
        scanf("%d%d%d", &u, &v, &val);
        G[u][v] = val;
//        G[v][u] = val;  //如果是无向图就得加上这句话
    }

    printf("enter the start:\n");
    int start;  scanf("%d", &start);

    ans.clear();        //首先要清空ans里面的残留数据
    memset(vis, 0, sizeof(vis));
    dfs(start);

    printf("the search path:\n");
    printf("%d", ans[0]);
    for(int i = 1; i < ans.size(); i++)         printf("-->%d", ans[i]);
    printf("\n");
    return 0;
}

当某种情况需要的节点过多,必须直接开较大的数组,如果依然用二维数组来保存临接矩阵,这时就会出现一下的异常:
这里写图片描述
所以采用如下方法将数组变成用vector的一维数组

/*对于节点过多的情况,直接开数组来表示临接矩阵就不可行了,
而采用临接链表的方式查找一条边又很麻烦,一下代码是基本就是临接链表做了一点改进*/
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 10000000 + 5;

struct Side {   //如果是有权图的话需要用结构体来存储权值
    int u, v, val;
    Side(int u = 0, int v = 0, int val = 0) : u(u), v(v), val(val) {}
};

vector<Side> sideVec;   //用这个vec来存储边
vector<int> G[maxn];    /*可以把这个vec看成类似临接链表中的主链表,也可以写成vector<vector<int> > G;能提升运行效率,因为初始化vector数组也需要大量时间,注意两个'>'要分开,不然编译器无法识别*/
vector<int> ans;            //用来存放节点访问顺序
int n, m, start;                        //节点的个数以及边的数量

void addSide(int a, int b, int cos) {
    sideVec.push_back(Side(a, b, cos));
    int dex = sideVec.size() - 1;
    G[a].push_back(dex);    //只保存在sideVec中的下标而不是节点b是为了能够访问到权值
}

void dfs(int start, bool vis[]) {
    vis[start] = true;
    for(int i = 0; i < G[start].size(); i++) {
        int idex = G[start][i];
        int v = sideVec[idex].v;    //v是与start相邻的节点
        if(!vis[v])     {ans.push_back(v);  dfs(v, vis);}
    }
}

int main()
{
    printf("enter the number of nodes and sides\n");
    scanf("%d%d", &n, &m);

    int u, v, val;
    printf(("create the matrix\n"));
    for(int i = 0; i < m; i++) {    //先创建图的整体结构
        scanf("%d%d%d", &u, &v, &val);
        addSide(u, v, val); //增加边
//        addSide(v, u, val); //暂且先假设为无向图
    }

    printf("enter the start node:\n");
    scanf("%d", &start);
    ans.clear();
    ans.push_back(start);

    bool vis[n + 5];
    memset(vis, 0, sizeof(vis));
    dfs(start, vis);

    printf("the search path:\n");
    printf("%d", ans[0]);
    for(int i = 1; i < ans.size(); i++)         printf("-->%d", ans[i]);
    printf("\n");
    return 0;
}

图的广搜

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

using namespace std;
const int maxn = 100;

int G[maxn][maxn], vis[maxn];
int n, m;   //图的节点和边
vector<int> ans;

void bfs(int start) {
    queue<int> q;
    q.push(start);
    memset(vis, 0, sizeof(vis));    vis[start] = 1;
    int u;

    while(!q.empty()) {
        u = q.front();
        ans.push_back(u);
        q.pop();
        for(int i = 0; i < n; i++)
            if(!vis[i] && G[u][i]) {q.push(i);      vis[i] = 1;}
    }
}

int main()
{
    printf("please enter the number of  nodes and sides:\n");
    scanf("%d", &n);    scanf("%d", &m);

    int u, v, val;      memset(G, 0, sizeof(G));        //首先要清空临接矩阵
    printf("crate the matrix:\n");
    for(int i = 0; i < m; i++) {        //建立临接矩阵
        scanf("%d%d%d", &u, &v, &val);
        G[u][v] = val;
        G[v][u] = val;  //如果是无向图就得加上这句话
    }

    printf("enter the start:\n");
    int start;  scanf("%d", &start);

    ans.clear();        //首先要清空ans里面的残留数据
    bfs(start);

    printf("the search path:\n");
    printf("%d", ans[0]);
    for(int i = 1; i < ans.size(); i++)         printf("-->%d", ans[i]);
    printf("\n");
    return 0;
}

对于处理数量较大节点的BFS同样如下:

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

using namespace std;
const int maxn = 10000000 + 5;

struct Side {   //如果是有权图的话需要用结构体来存储权值
    int u, v, val;
    Side(int u = 0, int v = 0, int val = 0) : u(u), v(v), val(val) {}
};

vector<Side> sideVec;   //用这个vec来存储边
vector<int> G[maxn];    //可以把这个vec看成类似临接链表中的主链表
vector<int> ans;            //用来存放节点访问顺序
int n, m, start;               //节点的个数以及边的数量

void addSide(int a, int b, int cos) {
    sideVec.push_back(Side(a, b, cos));
    int dex = sideVec.size() - 1;
    G[a].push_back(dex);    //只保存在sideVec中的下标而不是节点b是为了能够访问到权值
}

void bfs(int start, bool vis[]) {
    queue<int> q;
    q.push(start);  vis[start] = true;

    int u;
    while(!q.empty()) {
        u = q.front();  q.pop();
        for(int i = 0; i < G[u].size(); i++) {
            int idex = G[u][i];
            int v = sideVec[idex].v;
            if(!vis[v]) {
                ans.push_back(v);
                q.push(v);
                vis[v] = true;
            }
        }
    }
}

int main()
{
    printf("enter the number of nodes and sides\n");
    scanf("%d%d", &n, &m);

    int u, v, val;
    printf(("create the matrix\n"));
    for(int i = 0; i < m; i++) {    //先创建图的整体结构
        scanf("%d%d%d", &u, &v, &val);
        addSide(u, v, val); //增加边
//        addSide(v, u, val); //暂且先假设为无向图
    }

    printf("enter the start node:\n");
    scanf("%d", &start);
    ans.clear();
    ans.push_back(start);

    bool vis[n + 5];
    memset(vis, 0, sizeof(vis));
    bfs(start, vis);

    printf("the search path:\n");
    printf("%d", ans[0]);
    for(int i = 1; i < ans.size(); i++)         printf("-->%d", ans[i]);
    printf("\n");
    return 0;
}

接下来是例题,uvaOJ1599。上面处理大量节点的DFS/BFS代码基本来自于此题,照搬RuJia
题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51300
代码如下:

/*这道题可以用BFS解决,但是记录父节点的方法不能保证打印出来的路径字典序最小,所以解决方法是从终点倒着BFS,得到每个节点到终点的最小距离d[i](注意此时的图要看作无向无权图)。然后就可从起点开始BFS,到达一个节点时要保证d值减少1*/
#include <iostream>
#include <cstdio>
#include <vector>   //因为直接开数组占用的内存会过大而无法运行,所以使用vector
#include <queue>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 100000 + 5;
const int INF = 1000000000;

struct Side {
    int u, v, val;
    Side(int u = 0, int v = 0, int val = 0) : u(u), v(v), val(val) {}
};

vector<Side> sideVec;
vector<int> winLoad;
vector<int> graph[maxn];
int n, m, d[maxn];
int visit[maxn];

void addSide(int a, int b, int val) {
    sideVec.push_back(Side(a, b, val));
    int dex = sideVec.size() - 1;
    graph[a].push_back(dex);
}

void revBfs() {
    queue<int> q;
    memset(visit, 0, sizeof(visit));
    q.push(n - 1);      visit[n - 1] = 1;
    d[n-1] = 0;

    while(!q.empty()) {
        int k = q.front();  q.pop();
        for(int i = 0; i < graph[k].size(); i++) {
            int dex = graph[k][i];
            int u = sideVec[dex].v;
            if(!visit[u]) {
                visit[u] = 1;
                d[u] = d[k] + 1;
                q.push(u);
            }
        }
    }
}

void bfs() {
    memset(visit, 0, sizeof(visit));
    visit[0] = 1;
    winLoad.clear();

    vector<int> next;
    next.push_back(0);
    for(int i = 0; i < d[0]; i++) {
        int minVal = INF;
        for(int j = 0; j < next.size(); j++) {  //负责把最小的颜色编号存进winLoad中
            int u = next[j];
            for(int k = 0; k < graph[u].size(); k++) {
                int dex = graph[u][k];
                int v = sideVec[dex].v;
                if(d[u] == d[v] + 1)    minVal = min(minVal, sideVec[dex].val);
            }
        }

        winLoad.push_back(minVal);

        vector<int> next2;
        for(int j = 0; j < next.size(); j++) {
            int u = next[j];
            for(int k = 0; k < graph[u].size(); k++) {
                int dex = graph[u][k];
                int v = sideVec[dex].v;
                if(d[u] == d[v] + 1 && !visit[v] && sideVec[dex].val == minVal) {
                    visit[v] = 1;
                    next2.push_back(v);
                }
            }
        }
        next = next2;
    }

        printf("%d\n", winLoad.size());
        printf("%d", winLoad[0]);
        for(int i = 1; i < winLoad.size(); i++) printf(" %d", winLoad[i]);
        printf("\n");
}

int main()
{
    while(scanf("%d%d", &n, &m) == 2) {
        //sideVec.size();
        for(int i = 0; i < n; i++)     graph[i].clear();

        int a, b, val;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &a, &b, &val);
            addSide(a-1, b-1, val);
            addSide(b-1, a-1, val);
        }
        revBfs();    //从终点开始bfs,求出每个点到终点的最小无权距离
        bfs();


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值