PTA 电话聊天姐妹圈 (25分)(并查集+Hash)

新冠疫情期间,大家不能聚会,于是姐妹们就开始煲电话。姐妹们互相煲电话,自然就成了一个一个的圈子,为了区分哪些是真闺蜜,哪些是塑料姐妹情,我们对电话记录进行了跟踪,通过分析通话时间来确定亲密程度。我们这样设定,两个人之间所有的电话时间长度之和作为两个人亲密度的度量,一个姐妹圈是由三个或三个以上的女生组成,且所有成员的通话时间之和超过某个阈值K,姐妹圈中通话时间最长的那个就是该圈的核心。现在给一些通话清单,请找出姐妹圈的个数和姐妹圈里的核心。

输入格式:

第一行两个不超过1000的正整数N和K,分别表示电话的通数和阈值。随后的N行,按以下格式给出电话情况:

name1 name2 time

name1和name2使用3位大写字母来表示一个女生,time为不超过1000的整数,表示两人之间的通话时长。

输出格式:

对每一组输入,在第一行输出姐妹圈的个数。随后输出每一个姐妹圈的大姐大以及人数,中间用空格分隔。我们假设每个姐妹圈里的大姐大是唯一的。输出应按照大姐大的姓名的字母序升序输出。

输入样例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

输出样例1:

在这里给出相应的输出。例如:

2
AAA 3
GGG 3

输入样例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

输出样例2:

在这里给出相应的输出。例如:

0

解题

  1. 并查集
  2. Hash函数
  3. UnionSet时要将亲密度最大的作为根
  4. FindSet时将根与x比较交换根,使得亲密度最大的作为根

代码:

#include <iostream>					//7-10 电话聊天姐妹圈 (25分)
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 17576;		//26 ^ 3 = 17576

string revn[maxn];
bool vis[maxn];
int Set[maxn];
int Value[maxn];			//每个人的亲密度
int SumValue[maxn];			//集合的亲密度之和

int Hash(string name)
{
	return (name[0] - 'A') * 26 * 26 + (name[1] - 'A') * 26 + (name[2] - 'A');
}

int FindSet(int x)
{
	if(Set[x] < 0)
		return x;
	return FindSet(Set[x]);
}

void UnionSet(int R1, int R2)		//并集时, 使亲密度最大的作为根
{
	if(R1 == R2)
		return;
	if(Value[R1] < Value[R2])		//使R2为根
		Set[R2] += Set[R1], Set[R1] = R2;
	else							//使R1为根
		Set[R1] += Set[R2], Set[R2] = R1;
}

int main()
{
	memset(Set, -1, sizeof(Set));
	string name1, name2;
	int N, K, time;
	cin >> N >> K;
	K <<= 1;
	for (int i = 0; i < N; i++)
	{
		cin >> name1 >> name2 >> time;
		int a = Hash(name1);
		int b = Hash(name2);
		vis[a] = vis[b] = true; 					//出现的顶点
		revn[a] = name1, revn[b] = name2;			//下标对应name
		Value[a] += time, Value[b] += time;			//更新单人的亲密度

		/*调整Value最大的为根*/
		int r1 = FindSet(a);
		if(Value[r1] < Value[a])
			Set[a] = Set[r1], Set[r1] = a, r1 = a;
		int r2 = FindSet(b);
		if(Value[r2] < Value[b])
			Set[b] = Set[r2], Set[r2] = b, r2 = b;

		UnionSet(r1, r2);							//合并后的根
	}

	for (int i = 0; i < maxn; i++)
		if(vis[i])
			SumValue[FindSet(i)] += Value[i];		//计算每个姐妹圈的总通话时间

	vector<int> v;
	for (int i = 0; i < maxn; i++)
		if(vis[i] && Set[i] <= -3 && SumValue[i] > K)
			v.push_back(i);

	cout << v.size() << endl;
	for (int i = 0; i < v.size(); i++)
		cout << revn[v[i]] << " " << -Set[v[i]] << endl;

	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值