PTA甲级 1034 Head of a Gang (30分)

强烈推荐,刷PTA的朋友都认识一下柳神–PTA解法大佬

本文由参考于柳神博客写成

柳神的CSDN博客,这个可以搜索文章

柳神的个人博客,这个没有广告,但是不能搜索

还有就是非常非常有用的 算法笔记 全名是

算法笔记  上级训练实战指南		//这本都是PTA的题解
算法笔记

PS 今天也要加油鸭

在这里插入图片描述

题目原文

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.

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 threthold, 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.

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

生词如下:

PS:看懂了.在做了前几题之后,这题也有点会做了起来.

题目大意:

给你若干科树,要你求出其中所有的路径长度大于K的,而且总结点要大于2的数目,

并输出树的头 .这里树的头就是长度最长的结点

思路如下:

这里树的名称是AAA-ZZZ的,我们可以用一个散列.把这个名称转换成数字.或者用map来做也行

然后你可以选择数的遍历或者是查并集

分析:总的来说是一个判断一个图的连通分量的个数,用图的遍历解决,深度优先遍历。
1.因为给的是字母,要用两个map把它们转换成数字,从1开始排列命名所有不同的人的id,存储在两个map里面,一个字符串对应id,一个id对应字符串,方便查找,正好顺便统计了总共的人数idNumber。
2.建立两个数组,weight和G,分别存储每条边的权值和每个结点的权值,因为这两个题目中都要求得后判断。
3.用传递引用的方法深度优先dfs,这样传入的参数在dfs后还能保存想要求得的值
4.遍历过一条边之后就把这条边的权值设为0( G[u][v] = G[v][u] = 0;)防止出现回路遍历死循环

测试点段错误的原因

最多输入1000个,但是可能有两千个人.

所以数组要开的大一点

代码如下:

① 使用Map和查并集

#include<iostream>
#include<string>
#include<map>
#include<set>
using namespace std;
const int Max = 2048;
int n, k, index_array = 0, father[Max], RootNumber[Max], RootWeight[Max];
map<string, int> nameId,nameWeight;
map<int, string> Idname;
bool IsRoot[Max];
set<string> result;
void init() {						//初始化父亲集合,父亲结点的数量,父亲结点的重量
	for (int i = 0; i < Max; ++i) {
		father[i] = i;RootNumber[i] = 0;RootWeight[i] = 0;IsRoot[i] = false;
	}
}
int findFather(int x) {				//寻找父亲结点,还有压缩路径和寻找最大Weight结点的功能
	int a = x;
	int MaxWeight = 0,RootId=a;
	while (a != father[a]) {
		if (nameWeight[Idname[a]] > MaxWeight) {
			RootId = a;
			MaxWeight = nameWeight[Idname[a]];
		}
		a = father[a];
	}
	if (nameWeight[Idname[a]] >= MaxWeight) {
		RootId = a;MaxWeight = nameWeight[Idname[a]];
	}											//找到的一定是真正的根结点
	a = x;
	while (a != father[a]) {		//路径压缩,和找到根结点
		a = father[a];
		father[a] = RootId;
	}
	father[a] = RootId;father[x] = RootId;
	return RootId;
}	
void Union(int a,int b) {		//合并两个结点
	int Ra = findFather(a);
	int Rb = findFather(b);
	if (Ra != Rb) {
		if (nameWeight[Idname[a]] >=nameWeight[Idname[b]]) father[Rb] = Ra;
		else father[Ra] = Rb;
	}
	return;
}
bool FindName(string name) {			//判断一下这个数,有没有存在
	if (nameId.find(name) != nameId.end())	return true;
	else return false;
}
void init_array(string name,int weight) {	//初始化我们的nameId和Idname的函数
	if (!FindName(name)) {
		nameId[name] = index_array++;
		Idname[(index_array - 1)] = name;
		nameWeight[name] = weight;
	}
	else nameWeight[name] += weight;
}
int main(void) {
	cin >> n >> k;
	init();
	for (int i = 0; i < n; ++i) {
		string namea,nameb;
		int weight;
		cin >> namea >> nameb >> weight;
		init_array(namea, weight);
		init_array(nameb, weight);
		Union(nameId[namea], nameId[nameb]);
	}
	for (int i = 0; i < index_array; ++i) {	//每个图有多少结点.每个图的总质量
		RootNumber[findFather(i)]++;
		RootWeight[findFather(i)] += nameWeight[Idname[i]];
	}
	for (int i = 0; i < index_array; ++i) {
		if (IsRoot[findFather(i)] == false&&RootNumber[findFather(i)]>2&& RootWeight[findFather(i)]/2>k) {
			result.insert(Idname[findFather(i)]);
			IsRoot[findFather(i)] = true;
		}
	}
	cout << result.size()<<endl;
	for (auto i : result) 	cout << i <<" "<<RootNumber[nameId[i]]<< endl;
	return 0;
}

② 使用Map和DFS

#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<string>
using namespace std;
const int Max = 2010;
int n, k,weight,idweight[Max],indexArray=1,G[Max][Max];
bool vis[Max];
map<string, int> stringToInt,ans;
map<int, string> intToString;
void init(string a,int w) {
	if (stringToInt[a] == 0) {
		stringToInt[a] = indexArray++;
		intToString[indexArray - 1] = a;
	}
	idweight[stringToInt[a]] += w;
}
void dfs(int u,int& head, int& totalweight,int &numMember) {
	vis[u] = true;
	++numMember;
	if (idweight[u] > idweight[head])	head = u;
	for (int i = 1; i < indexArray; ++i) {
		if (G[u][i] > 0) {
			totalweight += G[u][i];
			G[u][i] = 0;
			G[i][u] = 0;
			if (vis[i] == false)	dfs(i, head, totalweight, numMember);
		}
	}
}
void dfsTrave() {
	for (int i = 1; i < indexArray; ++i) {
		if (vis[i] == false) {
			int head = i, totalweight = 0, numMember = 0;
			dfs(i, head, totalweight, numMember);
			if (totalweight > k && numMember > 2)	ans[intToString[head]] = numMember;
		}
	}
}
int main(void) {
	string a, b;
	cin >> n >> k;
	memset(vis, false, sizeof(vis));
	for(int i=0;i<n;++i){
		cin >> a >> b>>weight;
		init(a, weight);
		init(b, weight);
		G[stringToInt[a]][stringToInt[b]] += weight;
		G[stringToInt[b]][stringToInt[a]] += weight;
	}
	dfsTrave();
	cout << ans.size() << endl;
	for (auto it = ans.begin(); it != ans.end(); ++it) cout << it->first << " " << it->second << endl;
	return 0;
}

如果这篇文章对你有张帮助的话,可以用你高贵的小手给我点一个免费的赞吗

相信我,你也能变成光.

在这里插入图片描述

如果你有任何建议,或者是发现了我的错误,欢迎评论留言指出.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值