zoukankan      html  css  js  c++  java
  • PTA-7-6 列出连通集(并查集+DFS+BFS)

    本题考查点:

    • 图的并查集
    • 图的 BFS 和 DFS

    题目描述:

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

    输入格式:

    输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

    输出格式:

    按照"{ v1 v2 ... v**k }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

    输入样例:

    8 6
    0 7
    0 1
    2 0
    4 1
    2 4
    3 5
    

    输出样例:

    { 0 1 4 2 7 }
    { 3 5 }
    { 6 }
    { 0 1 2 7 4 }
    { 3 5 }
    { 6 }
    

    本题其实并不复杂,就是常规的图的并查集与DFS和BFS的结合,有关图的并查集和可以点击回顾。

    我们需要熟悉图的 BFS 和 DFS 思想,题目经常就是图的遍历加上某个条件的阈值设定。

    我们在进行 DFS 和 BFS 实现的时候,需要设定一个 vis[] 数组来保存该点是否已经访问过。

    而我们关于图的DFS 有常规思路如下:

    void DFS(u) {
      vis[u] = true;	// 设置为已访问
      for(从u出发能达到的所有顶点v)	// 枚举从u出发可以到达的所有顶点
        	if vis[v] == false	// 没有被访问
            	DFS(v)	// 递归访问
    }
    
    void DFSTravel(G) {
      for(G所有顶点u)
        if vis[u] == false
          DFS(u)
    }
    

    而同样,关于图的 BFS 有常规思路如下:

    void BFS(int u) {
      queue q;
      q.push(u);
      inq[u] = true;	// 设置 u 已经入队
      while(!q.empty()) {
        取出队首元素进行访问
        for(从u出发可到达所有顶点v)
          	if(inq[v] == false)
              将 v 入队
              inq[v] = true
      }
    }
    
    void BFSTravel() {
      for(G所有顶点u) {
        if(inq[u] == false)
          	BFS(u)
      }
    }
    

    而并查集我们可以不管左右树的高度直接实现并查集。

    完整代码如下:

    /*
        Author: Veeupup
        列出连通集
    
        给定一个有 N 个顶点和 E 条边的无向图,请用 DFS 和 BFS 分别列出其所有的连通集
        假设顶点从 0~N-1 编号,进行搜索时,我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点
    
        并查集 + DFS + BFS
    
        注意这里的 DFS 和 BFS 都要设置一个 访问数组 vis[] 来记录是否递归访问过或者是否入过队
    
     */
    #include <iostream>
    #include <cstdio>
    #include <cstdint>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    
    const int maxn = 12;
    
    int n, e;                   // 顶点数目和边数
    int G[maxn][maxn];          // 保存图
    bool visit[maxn] = {false}; // 记录是否访问过
    
    int father[maxn]; // 记录父亲节点
    
    void Initial()
    {
        fill(visit, visit + maxn, false);
        for (int i = 0; i < maxn; i++)
        { // 初始化父亲节点
            father[i] = i;
        }
    }
    
    // 查
    int findFather(int x)
    {
        while (x != father[x])
        {
            x = father[x];
        }
        return x;
    }
    
    // 并
    void Union(int x, int y)
    {
        x = findFather(x);
        y = findFather(y);
        if (x != y)
        {
            father[x] = y;
        }
    }
    
    // 深度优先遍历
    // 我们只需要从第一个结点开始
    void DFS(int nowVisit, vector<int> &sets)
    {
        for (int i = 0; i < n; i++)
        {
            if (G[nowVisit][i] != 0 && findFather(nowVisit) != findFather(i))
            {   // 如果二者连通 且 不在同一个集合中
                // 二者不在同一个集合中
                Union(nowVisit, i); // 合并到一个集合中
                sets.push_back(i);  // 加入到当前集合中
                if (visit[i] == false)
                { // 如果没有被DFS过,那么就深度优先遍历
                    visit[i] = true;
                    DFS(i, sets);
                }
            }
        }
    }
    
    void DFSTravel()
    {
        Initial();
        for (int i = 0; i < n; i++)
        {
            if (visit[i] == false)
            { // 如果没有被访问,那么深度优先遍历
                vector<int> sets;
                sets.push_back(i);
                visit[i] = true;
                DFS(i, sets);
                printf("{");
                for (int i = 0; i < sets.size(); i++)
                {
                    printf(" %d", sets[i]);
                }
                printf(" }
    ");
            }
        }
    }
    
    void BFS(int nowVisit, vector<int>& sets) {
        queue<int> myQ;
        myQ.push(nowVisit);
        visit[nowVisit] = true; // 设置已经访问过
        while (!myQ.empty())
        {
            int topId = myQ.front();
            myQ.pop();
            sets.push_back(topId);
            Union(nowVisit, topId); // 当前点合并到集合中
            for (int i = 0; i <= n; i++)
            {   // 当前点所连接的到的点不是在同一个集合中 , 没有入过队
                if(G[topId][i] != 0 && findFather(nowVisit) != findFather(i) && visit[i] == false) {
                    myQ.push(i);    // 加入到集合中
                    visit[i] = true;    // 已经入过队
                }
            }
        }
    }
    
    void BFSTravel() {
        Initial();
        for (int i = 0; i < n; i++)
        {
            if(visit[i] == false) {
                vector<int> sets;
                BFS(i, sets);
                printf("{");
                for (int i = 0; i < sets.size(); i++)
                {
                    printf(" %d", sets[i]);
                }
                printf(" }
    ");
            }
        }
        
    }
    
    int main()
    {
        freopen("data.txt", "r", stdin);
        memset(G, 0, sizeof(sizeof(int) * maxn * maxn));
        scanf("%d%d", &n, &e);
        int v1, v2; // 两条边的顶点
        for (int i = 0; i < e; i++)
        { // 读取边
            scanf("%d%d", &v1, &v2);
            G[v1][v2] = 1;
            G[v2][v1] = 1;
        }
        DFSTravel();
        BFSTravel();
        return 0;
    }
    
  • 相关阅读:
    494. Target Sum 添加标点符号求和
    636. Exclusive Time of Functions 进程的执行时间
    714. Best Time to Buy and Sell Stock with Transaction Fee有交易费的买卖股票
    377. Combination Sum IV 返回符合目标和的组数
    325. Maximum Size Subarray Sum Equals k 和等于k的最长子数组
    275. H-Index II 递增排序后的论文引用量
    274. H-Index论文引用量
    RabbitMQ学习之HelloWorld(1)
    java之struts2的数据处理
    java之struts2的action的创建方式
  • 原文地址:https://www.cnblogs.com/veeupup/p/12592806.html
Copyright © 2011-2022 走看看