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;
}
代码可能写的真的烂,有错误欢迎指出,以后学习道路上一起加油!!!