PAT A1034 Head of a Gang

19 篇文章 0 订阅
6 篇文章 0 订阅

一、题目大意

  1. PAT A1034
  2. 给出若干人之间的通话记录,这些通话将他们分成若干组。每个组的总边权值为该组内所有通话的时间之和,每个人的点权为该人参与的通话时间之和。现在只要某个组的总边权值大于一个阈值 k,并且组内人数大于 2,就将该组视为“犯罪团伙(gang)”,该组内点权最大的人视为头目。要求输出“犯罪团伙”的数目,并按头目姓名字典序的方式输出每个“犯罪团伙”的头目姓名和人数。

二、解题思路

  1. 首先解决姓名与编号的对应关系,编号与姓名的对应关系。具体用 map 实现。
  2. 需要获得每个人的点权,即与之相关的通话记录的时长之和,这个在读入数据时就可以处理,用 W[maxn] 来记录每个人的点权。
  3. 进行图的遍历。使用 DFS 遍历每个连通块,获取每个连通块的头目,成员个数,总边权值。进行判断,并将结果存储。

三、参考代码

#include<iostream>
#include<map>
#include<string>
using namespace std;
const int maxn = 2010;

int num_person = 0, k;
int W[maxn] = { 0 }, G[maxn][maxn] = { 0 };
bool vis[maxn] = { false };
map <string, int> string_int;
map <int, string> int_string;
map <string, int> gang;

int change(string s) {
	if (string_int.find(s) != string_int.end())
		return string_int[s];
	else {
		string_int[s] = num_person;
		int_string[num_person] = s;
		return num_person++;
	}
}
void DFS(int v, int &head, int &num_member, int &total_value) {
	vis[v] = true;
	num_member++;
	if (W[v] > W[head]) head = v;
	for (int i = 0; i < num_person; i++) {
		if (G[v][i]) {
			total_value += G[v][i];
			G[v][i] = G[i][v] = 0;
			if (!vis[i])
				DFS(i, head, num_member, total_value);
		}
	}
}
void DFS_trave() {
	for (int i = 0; i < num_person; i++) {
		if (!vis[i]) {
			int head = i, num_member = 0, total_value = 0;
			DFS(i, head, num_member, total_value);
			if (num_member > 2 && total_value > k)
				gang[int_string[head]] = num_member;
		}
	}
}

int main() {
	int n, t;
	cin >> n >> k;
	for (int i = 0; i < n; i++) {
		string s1, s2;
		cin >> s1 >> s2 >> t;
		int n1 = change(s1);
		int n2 = change(s2);
		W[n1] += t;
		W[n2] += t;
		G[n1][n2] += t;
		G[n2][n1] += t;
	}
	DFS_trave();
	cout << gang.size() << endl;
	for (auto it = gang.begin(); it != gang.end(); it++)
		cout << it->first << ' ' << it->second << endl;
	return 0;
}

四、解题感悟

  1. 本题也可以采用并查集解决。以后有时间再试试。
  2. 本题一开始觉得挺复杂的,照着书上的代码写了一遍,然后自己又重新写了一遍,才感觉理顺了一些。代码中关于图中有环的情况的处理值得借鉴。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值