题意:给出几组通话的人与通话时间,规定如果两人通话说明有联系,一个联系网络中的总通话时间超过阈值并且人数超过2人则把这个网络视为一个gang,其中通话时间最长的是head,输出每个gang的head和这个gang中的人数。
思路:并查集维护联通分量,用map映射一下集合和集合中的人,开数组记录一下每个人的通话时间即可。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
vector<string> v;
map<string, int> id;
int get_id(string x) {
if (id.count(x)) return id[x];
v.push_back(x);
return id[x] = v.size()-1;
}
string get_s(int i) {
return v[i];
}
const int MAX_N = 100000;
int par[MAX_N], n;
void init(int n) {
for (int i = 0; i < n; i++) {
par[i] = i;
}
}
int find(int x) {
if (par[x] == x) return x;
return par[x] = find(par[x]);
}
void uni(int x, int y) {
x = find(x); y = find(y);
if (x == y) return ;
par[x] = y;
}
int N, Y;
string a, b;
int t;
int cnt[MAX_N];
map<int, vector<int> > unio;
vector<string> ans;
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
cin >> N >> Y;
init(N);
for (int i = 0; i < N; i++) {
cin >> a >> b >> t;
int ida = get_id(a), idb = get_id(b);
cnt[ida] += t; cnt[idb] += t;
uni(ida, idb);
}
for (int i = 0; i < N; i++) {
int x = find(i);
unio[x].push_back(i);
}
for (auto it = unio.begin(); it != unio.end(); it++) {
int tmp = 0;
vector<int> &vv = it->second;
int ma = 0, ind = -1;
for (int i = 0; i < vv.size(); i++) {
tmp += cnt[vv[i]];
if (cnt[vv[i]] > ma) {
ma = cnt[vv[i]];
ind = vv[i];
}
}
if (vv.size() > 2 && tmp > Y*2) ans.push_back(get_s(ind));
}
sort(ans.begin(), ans.end());
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++) {
cout << ans[i] << " " << unio[find(get_id(ans[i]))].size() << endl;
}
return 0;
}