输入样例的点权、边权如下:
思路
- 为了得到某一个连通分量的总边权,用dfs遍历该连通分量。但是对于连通分量内成环的情况,不能仅仅标记某个结点是否已经访问过,例如对于F、H、G这三个结点,dfs遍历沿F->G->H遍历到结点H时,发现F已经访问过,就不将他们之间的边权10加到总边权中,最终返回的总边权只有50。
- 可以设置一个二维的bool数组标记某条边是否已经访问过,如果没访问过,将他们之前的边权加到总边权中。也可以在每次访问一条边时将这条边的权设为0,以避免重复访问。以下代码采用前者。
- 为了得到点权最大的结点,可以再次dfs遍历连通分量,找到点权最大的结点。
代码
#include<string>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
int callNum, threshold;
int id = 0;
unordered_map<string, int> name2id;
unordered_map<int, string> id2name;
int calls[2000][2000] = { 0 };
bool totalVisited[2000] = { false };
bool maxVisited[2000] = { false };
bool edgeVisited[2000][2000] = { false }; //记录两个人之前的通话是否访问过
struct node {
string name;
int memberNum;
}res[2000];
bool cmp(node n1, node n2) {
return n1.name < n2.name;
}
int memberCount = 0;
int getTotalWeight(int pos) { //返回gang的总权,同时记录人数
memberCount++;
totalVisited[pos] = true;
int total = 0;
for (int i = 0;i < id;i++) {
if (calls[pos][i] != 0) {
if (edgeVisited[pos][i] == false) { //边没访问过
total += calls[pos][i];
edgeVisited[pos][i] = true;
edgeVisited[i][pos] = true;
}
if (!totalVisited[i]) { //点没访问过
total += getTotalWeight(i);
}
}
}
return total;
}
int maxWeight = 0;
int maxPos = 0;
void findMaxPos(int pos) {
maxVisited[pos] = true;
int thisWeight = 0;
for (int i = 0;i < id;i++) {
if (calls[pos][i] != 0) {
thisWeight += calls[pos][i];
if (!maxVisited[i]) {
findMaxPos(i);
}
}
}
if (thisWeight > maxWeight) {
maxWeight = thisWeight;
maxPos = pos;
}
}
int getMaxPos(int pos) {
maxWeight = 0;
findMaxPos(pos);
return maxPos;
}
int main() {
scanf("%d %d\n", &callNum, &threshold);
for (int i = 0;i < callNum;i++) {
string n1, n2;
int time;
cin >> n1 >> n2 >> time;
cin.get();
if (name2id.count(n1) == 0) {
name2id[n1] = id;
id2name[id] = n1;
id++;
}
if (name2id.count(n2) == 0) {
name2id[n2] = id;
id2name[id] = n2;
id++;
}
int i1 = name2id[n1], i2 = name2id[n2];
calls[i1][i2] += time;
calls[i2][i1] += time;
}
int index = 0;
for (int i = 0;i < id;i++) {
if (!totalVisited[i]) {
memberCount = 0;
int total = getTotalWeight(i);
if (total > threshold && memberCount > 2) { //new gang
int pos = getMaxPos(i);
string name = id2name[pos];
res[index].memberNum = memberCount;
res[index].name = name;
index++;
}
}
}
sort(res, res + index, cmp);
printf("%d\n", index);
for (int i = 0;i < index;i++) {
cout << res[i].name << " " << res[i].memberNum << endl;
}
}
二刷:
#include<iostream>
#include<string>
#include<algorithm>
#include<unordered_map>
#include<vector>
#include<unordered_set>
#include<map>
using namespace std;
int callNum, threshold;
unordered_map<string, unordered_map<string, int> > call;
unordered_map<string, unordered_set<string> > edgeVisited;
unordered_set<string> vertexVisited;
unordered_map<string, int> vertexWeight;
map<string, int> res;
int totalEdgeWeight, memberCount;
string head;
void dfs(string cur) {
if (vertexVisited.count(cur) == 0) {
vertexVisited.insert(cur);
if (vertexWeight[cur] > vertexWeight[head])
head = cur;
memberCount++;
}
for (auto it : call[cur]) {
if (edgeVisited[cur].count(it.first) == 0) {
edgeVisited[cur].insert(it.first);
edgeVisited[it.first].insert(cur);
totalEdgeWeight += it.second;
dfs(it.first);
}
}
}
int main() {
cin >> callNum >> threshold;
for (int i = 0;i < callNum;i++) {
string a, b;
int time;
cin >> a >> b >> time;
call[a][b] += time;
call[b][a] += time;
}
//calculate total weight of every person
for (auto it1: call) {
for (auto it2 : it1.second) {
vertexWeight[it1.first] += it2.second;
}
}
//calculate total weight of clusters of people
for (auto it : call) {
if (vertexVisited.count(it.first) == 0) {
totalEdgeWeight = 0;
head = it.first;
memberCount = 0;
dfs(it.first);
if (totalEdgeWeight > threshold && memberCount > 2)
res[head] = memberCount;
}
}
cout << res.size() << endl;
for (auto it : res)
cout << it.first << " " << it.second << endl;
}