1034 Head of a Gang (30分)

本文介绍了一种基于图论的团伙识别算法,通过深度优先搜索(DFS)遍历无向图,寻找满足特定条件的连通块,即所谓的团伙。算法首先读取节点数量和阈值k,然后输入节点间的连接及通话时间,存储为无向图。接着,遍历图中每个节点,使用DFS算法找出所有连通块,并计算连通块内边的总权重。如果连通块的大小超过3且总权重超过k,则将其认定为团伙。最后,确定团伙内的头目(通话时间最长者),并输出团伙的头目和人数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>

using namespace std;

int n, k;
unordered_map<string, vector<pair<string, int>>> g;
unordered_map<string, int> total;  //所有人的通话总时间
unordered_map<string, bool> st;   //判重数组,保证每个点只被搜索一次

int dfs(string ver, vector<string> &nodes)
{
    st[ver] = true;
    nodes.push_back(ver);

    int sum = 0;
    for (auto edge : g[ver])
    {
        sum += edge.second;
        string cur = edge.first;   //寻找与ver连通的边
        if (!st[cur]) sum += dfs(cur, nodes);
    }

    return sum;
}

int main()
{
    cin >> n >> k;
    while (n -- )
    {
        string a, b;
        int t;
        cin >> a >> b >> t;
        g[a].push_back({b, t});  //无向图相当于存两条有向边
        g[b].push_back({a, t});
        total[a] += t;
        total[b] += t;
    }

    vector<pair<string, int>> res;  ///string存头目的名字,int存团伙的人数
    for (auto item : total)  //遍历每个人
    {
        string ver = item.first;
        vector<string> nodes;   //存某个连通块里的所有人
        int sum = dfs(ver, nodes) / 2;

        if (nodes.size() > 2 && sum > k)  //判断是否满足成为团队的条件
        {
            string boss = nodes[0];   //寻找总通话时间最长的人
            for (string node : nodes)
                if (total[boss] < total[node])
                    boss = node;
            res.push_back({boss, (int)nodes.size()});  //把头目和团队人数存入答案数组
        }
    }

    sort(res.begin(), res.end());   //对每个团伙按头目的字典序排序

    cout << res.size() << endl;   //输出答案数组的个数
    for (auto item : res) cout << item.first << ' ' << item.second << endl;
    //遍历答案数组,依次输出头目名和团队人数
    return 0;
}

思路:

  1. 一个帮派就是一个连通块,该连通块最少有三个点,连通块所有边的长度大于阈值k
  2. 找连通块:图的搜索 DFS,同时要记录:总边权(判断是否大于k),所有点的名字(枚举所有点看哪个点的通话时间最久)
  3. 把无向边存储为两条有向边,故最后边权要除以2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值