1034 Head of a Gang带权并查集

1034 Head of a Gang

PAT甲级带权并查集

题目传送门
并查集基础(通俗易懂) 原文链接

先扯一下,本人的第一篇博客,写的不好有错误请dalao指出,有问题可以一起讨论。这题并不是特别难,但我第一次写完完整的带权并查集,纪念一下。并查集还是挺基础的,主要就是init()、find(x)、join(x,y)三个函数,推荐看下链接,通俗易懂。当初大一上不是很理解,现在觉得当初好蠢。

在这里插入图片描述

思路: 就是tim记录每个人的通话时间,然后用并查集合并团伙,当一个团伙人数大于2并且总通话时间大于k,就输出团伙的头(tim通话时间最长的人),这里让通话时间最长的人作为祖先。详情见注释

#include<bits/stdc++.h>
using namespace std;
map<string,string> pre; //定义节点 该节点人名映射其祖先 
map<string,int> tim,tot,group; //tim:每个人通话的时间 tot:一个团伙的总时间 group:用来存一个团伙的人数 
struct node{ //用来存输出的答案 
 int num;  //团伙人数 
 string head; //团伙head的名字 
};
vector<node> v;
string find(string x){  //查找祖先函数 
 string temp=x;      
 while(pre[x]!=x) x=pre[x]; //一直找到该节点祖先 
 if(tim[temp]>tim[x]){ //如果这个人通话时间比现在这个团伙的head还多,就将该节点设置为该团伙的head 
  pre[x]=temp;
  pre[temp]=temp;
  return temp;
 }
 return x;  
}
void join(string x,string y){  //合并(基本裸的并查集) 
 string fx=find(x); 
 string fy=find(y);
 if(fx!=fy){//合并时注意讲通话时间短的节点祖先设置为通话时间长的 
  if(tim[fx]>tim[fy]) pre[fy]=pre[fx]; 
  else pre[fx]=fy;
 }
}
int main()
{
 int n,k;
 cin>>n>>k;
 for(int i=0;i<n;i++){
  string a,b;
  int val;
  cin>>a>>b>>val;
  if(pre.find(a)==pre.end()) pre[a]=a; //这个人名没出现,就将其祖先初始化自己; 
  if(pre.find(b)==pre.end()) pre[b]=b;// 这个人名没出现,就将其祖先初始化自己; 
  tim[a]+=val;  //tim记录每个人的通话时间 
  tim[b]+=val;
  join(a,b);  //合并团伙 
 }
 for(map<string,string>::iterator it=pre.begin();it!=pre.end();it++){//遍历每个人,查找每个团伙的head 
  tot[find(it->first)]+=tim[it->first]; //it->first对应这个人名字 
  group[find(it->first)]++; //tot:用该团伙的head映射该团伙总通话时间  group同理,这个团伙人数++ 
 }
 for(map<string,int>::iterator it=group.begin();it!=group.end();it++){ //遍历每个团伙 
  if(it->second>2&&tot[it->first]/2>k){  //这里it->first对应的是该团伙的head、it->second对应的是 该团伙总通话时间 
   node temp; //符合条件(注:这里每个人通话时间都被加了一边,整个团伙通话时间要除2)
   temp.head=it->first; 
   temp.num=it->second;
   v.push_back(temp);  //装入vector 
  }
 }
 cout<<v.size()<<'\n'; 
 for(int i=0;i<v.size();i++){
  cout<<v[i].head<<' '<<v[i].num<<'\n';
 }
 return 0;
}

代码可能写的真的烂,有错误欢迎指出,以后学习道路上一起加油!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值