一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
警察找到团伙头目的一种方法是检查人们的通话。
如果 A 和 B 之间有通话,我们就说 A 和 B 是相关的。并且关联具有传递性,即如果 A 与 B 关联,B 与 C 关联,那么 A 与 C 也是关联的。
关联权重定义为两人之间所有通话的总时间长度。
一个“帮派”是一个由至少3个相互关联的人组成的群体,并且其总关联权重大于给定的阈值 K。
在每个帮派中,总权重最大的就是头目,数据保证每个帮派中总权重最大的人是唯一的。
你需要确定各个帮派以及帮派头目。
数据范围
1≤N,K≤1000
输入格式:
第一行包含两个整数 N 和 K,表示通话数量以及权重阈值。
接下来 N 行,每行采用如下形式描述通话:
Name1 Name2 Time
Name1 和 Name2 是通话的两人的名字,Time 是通话时间。
名字的长度固定为 3,且只包含大写字母。
时间是一个不超过 1000 的正整数。
输出格式:
第一行输出帮派数量。
接下来每行输出一个帮派的信息,包括帮派头目名字以及帮派人数。
帮派信息按头目名字字典序输出。
输入样例1:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
输出样例1:
2
AAA 3
GGG 3
输入样例2:
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
HHH FFF 10
输出样例2:
0
分析
题意
各个名字之间相互通话,相当于名字与名字之间两两有联系,将各个两两有联系的名字用链子串起来组成一个集合,求集合的个数,和各个集合中名字通话的最长时间。
思路
- 根据题意分析,可以想到用并查集。
- 可以直接将时间大的作为父亲结点,这样只需要寻找每个集合的根节点就能找到大姐大了。
- 由于测试数据的不同,会出现两个集合的情况,但这两个集合实际上属于一个团伙,所以得注意合并的问题题 代码如下:
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <set>
using namespace std;
const int N = 2010;
struct Edge
{
int a, b, c;
}edges[N];
int n, k, idx;
string names[N];
int t[N], f[N], cnt[N], w[N];
unordered_map<string, int> id;
void init()//并查集的初始化
{
for(int i = 0; i < N; i++) {
f[i] = i;
cnt[i] = 1;
}
}
int get(string name)
{
if(id.count(name)) {//被查找元素的个数为>0;
return id[name];
}
id[name] = idx;
names[idx] = name;//将姓名转化为数字
return idx++;
}
int find(int x)
{
return f[x] = f[x] == x ? x : find(f[x]);//并查集的查找。
}
void merge(int a, int b, int c)
{
int fa = find(a), fb = find(b);//找到两个名字的根节点
if(w[fa] < w[fb]) {
swap(fa, fb);//将时间大的放前面(让老大当上根节点)
}
f[fb] = fa;
if(fa != fb) {//根节点不同合并并查集
t[fa] += t[fb];
cnt[fa] += cnt[fb];
}
t[fa] += c;//记录时间
}
int main()
{
init();
cin >> n >> k;
for (int i = 0; i < n; i ++ )
{
string s1, s2;
int time;
cin >> s1 >> s2 >> time;
int a = get(s1), b = get(s2);
w[a] += time, w[b] += time;//记录每个名字的时间
edges[i] = {a, b, time};//放入结构体
}
for (int i = 0; i < n; i ++ )
{
int a = edges[i].a, b = edges[i].b, c = edges[i].c;
merge(a, b, c);
}
set<pair<string, int>> res;
for(int i = 0; i < idx; i++)
{
if(find(i) == i && t[i] > k && cnt[i] >= 3) {//如果可以满足条件
res.insert({names[i], cnt[i]});//大姐大名字和相应的人数放进set中。
}
}
cout << res.size() << endl;
for(auto x : res) {
cout << x.first << ' ' << x.second << endl;
}
return 0;
}