PAT甲级1034 Head of a Gang//DFS运用

One way that the police finds the head of a gang is to check people’s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A “Gang” is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threshold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.

翻译:警察找到团伙首领的一种方法就是检查人们的电话记录。如果在A和B之间通过电话,则我们称A和B是关联的。关系的权重定义为两个人之间总的通话长度。而团伙是一个由超过两个相互联系的人组成的群体,并且他们的总权重大于给定的阈值K。在每个团伙中,那位有着最高权重的人就是首领。现在给定一串通话记录,你要去找出团后和首领。

Input Specification:

Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threshold, respectively. Then N lines follow, each in the following format:
Name1 Name2 Time
where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call. A name is a string of three capital letters chosen from A-Z. A time length is a positive integer which is no more than 1000 minutes.

翻译:每个输入文件包含一个样例。在每个样例中,第一行包括两个整数N和K,分别是通话记录数量和权重阈值。接着N行,每行的格式是Name1 Name2 Time。Name1和Name2是电话两端人的姓名,Time是通话时长,名字由3个A-Z中的大写字母组成。时长是不超过1000分钟的正整数

Output Specification:

For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.

翻译:每个测试样例中,第一行输出团伙数量。接着对每个帮派,在一行中输出该帮派中首领的姓名和团伙成员数量。题目保证每个帮派有独一无二的首领。输出必须按照首领名字的字母表排序

Sample Input 1:

8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10

Sample Output 1:

2
AAA 3
GGG 3

Sample Input 2:

8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 2:
0

示例讲解

示例一
                                         30
            A             D            F ——— G
         40/ \30          |75         10\   /20
          C   B           E               H
总权重:    70            75              60

三组总权重均超过了59,但是其中只有第一和第三组构成团伙,因为第二组只有两个成员。第一组首领是A,因为点权为70是最大的,同理第三组的首领是G,点权为50

思路

用DFS解决,遍历一个图就记录该图成员数以及总权重,如果总权重大于给定的K且成员数大于N,则将该图的首领和成员数映射放入散列表,最后按要求输出

#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
#include <map>
using namespace std;
int n, k, num, G[2010][2010] = {0}, weight[2010] = {0}; //用G存储图,weight表示每个点的点权
map<string, int> sti;
map<int, string> its;
map<int, int> visit;
map<string, int> Gang;
int change(string s);
void dfs(int now, int &head, int &members, int &value);
void dfs_trav();
int main()
{
	cin >> n >> k;
	for (int i = 0; i < n; i++)
	{
		int time;
		string a, b;
		cin >> a >> b >> time;
		int id_a = change(a); //这里让字符和整型形成一个映射,方便存储到图中,比如A对应1,B对应2等等
		int id_b = change(b);
		G[id_a][id_b] += time; //增加边权
		G[id_b][id_a] += time;
		weight[id_a] += time; //增加点权
		weight[id_b] += time;
	}
	dfs_trav();
	cout << Gang.size() << endl;
	for (map<string, int>::iterator it = Gang.begin(); it != Gang.end(); it++)
		cout << it -> first << ' ' << it -> second << endl;
	system("pause");
	return 0;
}
int change(string s)
{
	if (sti.find(s) != sti.end())
		return sti[s];
	else
	{
		sti[s] = num;
		its[num] = s; //同时让整型对应名字,方便后面使用
		return num++;
	}
}
void dfs_trav()
{
	for (int i = 0; i < num; i++)
	{
		if (visit[i] == false)
		{
			int head = i, members = 0, value = 0;
			dfs(i, head, members, value);
			if (members > 2 && value > k)
				Gang[its[head]] = members;
		}
	}
}
void dfs(int now, int &head, int &members, int &value) //注意用引用
{
	members++;
	visit[now] = true;
	if (weight[now] > weight[head]) //如果当前结点的权重比当前头目的还大,则更行头目
		head = now;
	for (int i = 0; i < num; i++)
	{
		if (G[now][i] > 0) //如果当前结点到i存在路径
		{
			value += G[now][i]; //总边权加上该条边的边权
			G[now][i] = G[i][now] = 0; //一定要删除这条边
			//如果不删,假如这里加上了2到3的边权G[2][3],后面还会加上G[3][2]即同一条边的边权
			if (visit[i] == false)
				dfs(i, head, members, value);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值