PAT1034 Head of a Gang (30)(并查集)
题意:
给出n次通话记录,当通话的人数超过2人并且通话总时长超过k时,这些人就是犯罪团伙,其中通话时间最大的人是头目,要求按字母序输出头目和团伙人数
思路:
就是并查集,将两两通话的人关联在一起,因为通话的人的姓名是按三位字母给出的,所以要离散化,并且对应要用一些STL保存映射。我自己写的时候有两个点没过,后来改过了,错误原因写在下面注释里了。网上的代码也有用DFS找连通分量做的。
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int INF = 0xfffff;
const int maxn = 2010; //这里开1005会出现段错误,因为是n个通话可能有2n个人
map<string, int> gang;
map<int, string> gangName;
int gangTime[maxn];
int p[maxn];
int n, k,pos=0;
vector<int> head[maxn];
set<string> res;
void init() {
for (int i = 0; i < maxn; i++) {
p[i] = i;
head[i].push_back(i);
}
}
int find(int x) {
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
p[x] = y;
for (auto i = head[x].begin(); i != head[x].end(); i++) {
head[y].push_back(*i);
}
head[x].clear(); //这里必须清零
}
}
int main() {
scanf("%d%d", &n, &k);
init();
for (int i = 0; i < n; i++) {
string name1, name2;
int time;
cin >> name1 >> name2 >> time;
if (gang.find(name1) == gang.end()) {
gang[name1] = pos;
gangName[pos++] = name1;
}
if (gang.find(name2) == gang.end()) {
gang[name2] = pos;
gangName[pos++] = name2;
}
gangTime[gang[name1]] += time;
gangTime[gang[name2]] += time;
merge(gang[name1], gang[name2]);
}
for (int i = 0; i < pos; i++) {
if (head[i].size() > 2) {
int maxTime = -1, index;
int totalTime = 0;
for (auto x : head[i]) {
if (maxTime < gangTime[x]) {
maxTime = gangTime[x];
index = x;
}
totalTime += gangTime[x];
}
if (totalTime > 2*k) {
res.insert(gangName[index]);
}
}
}
if (res.empty())
cout << 0 << endl;
else {
cout << res.size() << endl;
for (auto x : res) {
int h = find(gang[x]);
cout << x << " " << head[h].size() << endl;
}
}
return 0;
}