PAT 1034 Head of a Gang(图遍历+BFS)

题目

https://www.patest.cn/contests/pat-a-practise/1034

题意:给出1000条以内的通话记录A B和权值w,如果一个团伙人数超过2人并且通话总权值超过阈值k,令团伙里面的自身权值的最大值为头目,输出所有满足条件的团伙的头目,和他们团伙里面的人数。

解题思路

数据结构

  • 邻接表存放图的邻接关系,weight数组存放节点权重

    • 邻接节点 = 它通话过的所有节点
    • 每个节点的权重 = 它所在的通话记录时间之和
  • map<string, int>vector<string>形成双射,为字符串分配整数值,同时将整数值对应到字符串。

算法

用BFS实现对图的遍历,注意到可能有多个连通分量,因此涉及到调用多次BFS。

在BFS中,每次出队就累加团队人数、累加团队总权重、更新该团队里的最大权重,然后将该节点的邻接节点入队(注意一定是未访问过的)。

需要注意的是,输入的路径数N最大值为1000,所以最多可能要2000个节点!(否则会出现测试点4的段错误)

AC代码

#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 2005; //路径数为1000,但节点数可能为2000!

map<string, int> getStrIndex; //字符串对应的索引
string s[maxn]; //s[1..cnt]存放索引对应的字符串
map<string, int> ans; //存放输出结果,自动排序
int cnt = 0;

vector<int> adj[maxn]; //邻接表
int weight[maxn]; //每个节点的权重
bool visited[maxn]; //标记每个节点是否访问过

void BFS(int start, int &head, int &member, int &sum)
{
    queue<int> q;
    q.push(start);
    visited[start] = true;
    int out, son;
    int cur_max = 0; //最大值
    while (!q.empty())
    {
        out = q.front(); q.pop(); //队首出队
        member++; //群人数累加
        sum += weight[out]; //群总权重累加
        if (weight[out] > cur_max) //更新最大权重
        {
            cur_max = weight[out];
            head = out;
        }
        for (int i = 0; i < adj[out].size(); ++i) //邻接节点入队
        {
            son = adj[out][i];
            if (!visited[son]) //必须是未访问过的
            {
                q.push(son);
                visited[son] = true;
            }
        }
    }
}

void init(int n) //初始化全局变量
{
    for (int i = 0; i < maxn; ++i)
    {
        weight[i] = 0;
        visited[i] = false;
        adj[i].clear();
    }
}

int alloc_index(const string &x) //获得字符串s的索引
{
    if (getStrIndex[x] == 0) //新的字符串
    {
        getStrIndex[x] = ++cnt;
        s[cnt] = x;
    }
    return getStrIndex[x]; //返回索引值
}


void solve(int n, int threshold)
{
    init(n);
    string a, b;
    int w;
    for (int i = 0; i < n; ++i) //输入
    {
        cin >> a >> b >> w;
        int idxa = alloc_index(a), idxb = alloc_index(b);
        weight[idxa] += w;
        weight[idxb] += w;
        adj[idxa].push_back(idxb); //标记邻接
        adj[idxb].push_back(idxa);
    }
    for (int i = 1; i <= cnt; ++i)
    {
        if (!visited[i]) //出现新的连通集
        {
            int head = 0, member = 0, sum = 0;
            BFS(i, head, member, sum); //传参调用BFS
            if (member > 2 && (sum>>1) > threshold) //群人数大于2且群权重大于阈值
                ans[s[head]] = member;
        }
    }
    cout << ans.size() << endl; //map自动排序
    for (auto it = ans.begin(); it != ans.end(); ++it)
        cout << it->first << ' ' << it->second << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    int n, k;
    cin >> n >> k;
    solve(n, k);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值