1034 Head of a Gang (30分)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输入样例的点权、边权如下:
在这里插入图片描述

思路
  • 为了得到某一个连通分量的总边权,用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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值