题目
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);
}