[PAT Class A DFS adjacency table C++ implementation] 1034 Head of a Gang (30 points)

The main idea of ​​the topic is:

  • Enter N and K (N is the number of edges in the graph, K is the threshold)

  • Then enter N edges: the weight of the arc start and end arc

  • If a connected block satisfies:

    • The sum of all edge weights must be greater than K
    • The number of people (the number of vertices) is greater than 2 (3 or more),

      then the connected block is a Gang (and the head of the Gang is the vertex with the largest weight)

Output the names of the heads of all Gangs in this graph (the names of the most weighted vertices) and the number of members of this Gang (the number of vertices in a single connected block)

The weight of the point in the question is equal to the sum of the weights of all the edges connected to it


After thinking about it all night, I finally came up with a data structure suitable for my DFS adjacency list.

  • When it is difficult to use vertex information 类型为VexTypeas an index, it needs to be map<VexType, vector<ArcNode>> G;replaced vector<VexType> G[顶点个数]to make a mapping between vertex information VexTypeand directed edge setsvector<ArcNode>
  • Because it is a map, the edges without out-of-degrees will not appear in the above G. If you want to access the weights of the vertices, you need an additional vertex tablemap<VexType, int> V
  • Because it will not ArcNode边perform complex operations, but only access operations, you can ArcNodeadd an access mark to it vis(As for why not set the vertex into a structure and then also set an access mark vis, I think it is because of the need to do the vertex Too many operations, set it as a structure to increase complexity)
  • When the vertex information is a string, you can hash the string and then use the vector, you can use the original form of the graph data structure (try this later)
# include <iostream>
# include <vector>
# include <map>
using namespace std;

/*
如果一个连通块:
    所有边权值的sum必须要大于K
    人数为大于2(3个及以上)
满足以上两个条件,那么就是一个Gang(而Gang的头头就是最大权值的顶点)

然后输出Gang的总个数 and
所有头头的名字和当前头头的Gang的总人数
*/


typedef string VexType;

// 边结点
struct ArcNode{
    
    
    VexType name; // 顶点名字(边的弧头)
    int weight;   // 以顶点为弧尾的边的权重
    bool vis;     // 标记当前边是否被访问过

    ArcNode(VexType _n, int _w, bool _v): name(_n), weight(_w), vis(_v){
    
    }
};

// 当难以将顶点信息做为索引的时候,就需要用map做成代替vector(顶点信息是字符串时,可以对字符串进行hash再使用vector)
// V[u]得到的是顶点u的权值
map<VexType, int> V; // 顶点表(顶点名字:顶点权重)

// 当要访问没有没有出度的顶点时,因为map对这些没加入map的使用默认初始化,所以没有出度的顶点的vector为空,也就不影响了
// G[u]得到的是u的邻接点的vector(或者说有向边集合)
map<VexType, vector<ArcNode>> G; // 邻接表(顶点名字:可达的邻接点集合(有的顶点没有出度,也就不会在这个映射里了))
map<VexType, bool> visited; // 标记顶点是否访问
map<VexType, int> Gang; // 某Gang的头头:帮派权重总和

int N, K;

// 因为一次调用DFS都会遍历一整个连通块,所以下面三个变量是针对一个连通块的
// maxWeightVex:最大权值点    sumArcWeight:边权之和  numPeople当前连通块的顶点个数
void DFS(VexType u, VexType &maxWeightVex, int &sumArcWeight, int &numPeople){
    
    
    // 访问u(这里对点u进行处理访问)
    numPeople++;
    if(V[u] > V[maxWeightVex]) // 如果当前顶点的权值大于之前找到的最大权值
        maxWeightVex = u;
    visited[u] = true;

    // 遍历u的所有邻接点(这里对从点u出去的边进行处理访问)
    for(ArcNode &arcnode: G[u]){
    
     // 似乎不用加引用也可以
        VexType v = arcnode.name; // v是邻接点的名字
        if(arcnode.vis == false){
    
     // 如果当前边的边权还没加入sumArcWeight中(也就是没被访问过),那就加入并标记已访问
            sumArcWeight += arcnode.weight;
            arcnode.vis = true;
        }
        // 如果u的当前邻接点未被访问就去访问,若已访问就进入下一次循环判断下一个邻接点
        if(visited[v] == false){
    
    
            DFS(v, maxWeightVex, sumArcWeight, numPeople); // 去到邻接点v访问邻接点v
        }
    }
}

void DFSTraverse(){
    
    
    /* 遍历不同的连通块
    (通过寻找未访问过的节点,然后DFS访问它,然后它所在的连通块中的所有结点就会被访问,
    于是下一次寻找的未访问的顶点一定是别的连通块)
    */
    for(auto p:  V){
    
     // 遍历顶点表
        VexType u = p.first; // u是顶点名字
        if(visited[u] == false){
    
    
            // maxWVex:最大权值点    sumW:边权之和    numPeople当前连通块的顶点个数
            VexType maxWVex = u;
            int sumW = 0;
            int numPeople = 0;
            DFS(u ,maxWVex, sumW, numPeople);

            // 如果连通块总人数3人以上 && 总边权大于K,让就加入Gang集合
            if(numPeople >= 3 && sumW > K)
                Gang[maxWVex] = numPeople;
        }
    }
}




int main(){
    
    
    cin >> N >> K;
    for(int i=0;i<N;++i){
    
    
        VexType name1, name2;
        int weight;
        cin >> name1 >> name2 >> weight;
        G[name1].push_back({
    
    name2, weight, false}); // 建立邻接表,设置边权和初始化为未访问过
        V[name1] += weight; // 设置点权
        V[name2] += weight; // 设置点权
    }

    DFSTraverse();

    // 然后输出Gang的总个数
    cout << Gang.size() << endl;
    for(auto p: Gang){
    
    
        // 输出头头的名字和当前头头的Gang的总人数
        cout << p.first << " " << p.second << endl;
    }
    
    return 0;
}

The template of the template DFS adjacency table is attached below:

# include <iostream>
# include <vector>
# include <map>
using namespace std;

typedef string VexType;

// 边结点
struct ArcNode{
    
    
    VexType name; // 顶点名字(边的弧头)
    int weight;   // 以顶点为弧尾的边的权重
    bool vis;     // 标记当前边是否被访问过
    ArcNode(VexType _n, int _w, bool _v): name(_n), weight(_w), vis(_v){
    
    }
};

// 当难以将顶点信息做为索引的时候,就需要用map做成代替vector(顶点信息是字符串时,可以对字符串进行hash再使用vector)
map<VexType, int> V; // 顶点表(顶点名字:顶点权重)
// 当要访问没有没有出度的顶点时,因为map对这些没加入map的使用默认初始化,所以没有出度的顶点的vector为空,也就不影响了
// G[u]得到的是u的邻接点的vector
map<VexType, vector<ArcNode>> G; // 邻接表(顶点名字:可达的邻接点集合(有的顶点没有出度,也就不会在这个映射里了))
map<VexType, bool> visited; // 标记顶点是否访问
int N; // 边的个数

/* 一次调用DFS都会遍历一整个连通块
    >>> 要统计当前连通块的数据的话可以在参数中添加变量(记得统计的变量是引用【如果不是全局变量的话】),
    >>> 如果是对点做统计那就在访问点那里写语句,
    >>> 如果是对边做统计的话就在访问边那里写) 
*/
void DFS(VexType u){
    
    
    // 访问u(这里对点u进行处理访问)
    cout << "点" <<u << endl;
    visited[u] = true;

    // 遍历u的所有邻接点(这里对从点u出去的边进行处理访问)
    for(ArcNode &arcnode: G[u]){
    
     // 似乎不用加引用也可以
        VexType v = arcnode.name; // v是u邻接点的名字
        if(arcnode.vis == false){
    
     // 如果当前边没被访问过,那就访问并标记
            // 访问边
            cout << "边" <<'[' << u << "-" << v << ']' << endl;
            arcnode.vis = true;
        }
        // 如果u的当前邻接点未被访问就去访问,若已访问就进入下一次循环判断下一个邻接点
        if(visited[v] == false){
    
    
            DFS(v); // 去到邻接点v访问邻接点v
        }
    }
}

void DFSTraverse(){
    
    
    /* 遍历不同的连通块
    (通过寻找未访问过的节点,然后DFS访问它,然后它所在的连通块中的所有结点就会被访问,
    于是下一次寻找的未访问的顶点一定是别的连通块)
    */
    int cnt = 0;
    for(auto p:  V){
    
     // 遍历顶点表
        VexType u = p.first; // u是顶点名字
        // 有多少个连通块这个if里面的语句就会被执行多少次
        if(visited[u] == false){
    
    
            // 可以在这里设立对一个连通块统计的变量
            printf("\n连通块%d:\n", (cnt++)+1);
            DFS(u);
            // 可以在这里处理在DFS里统计的数据
            cout << endl;
        }
    }
}




int main(){
    
    
    cin >> N >> K;
    for(int i=0;i<N;++i){
    
    
        VexType name1, name2;
        int weight;

        cin >> name1 >> name2 >> weight;
        G[name1].push_back({
    
    name2, weight, false}); // 建立邻接表,设置边权和初始化为未访问过
        V[name1] += weight; // 设置点权
        V[name2] += weight; // 设置点权
    }

    DFSTraverse();

    return 0;
}

Guess you like

Origin blog.csdn.net/MYMarcoreus/article/details/113706635