使用并查集和dfs都可以解决这个问题。
如下是并查集解决的过程。
相对于普通问题,主要是Union函数发生了变化
#include<iostream>
#include<map>
#include<string>
using namespace std;
//头是要点权最高的来。
//边权怎么记录?
const int maxn=1001;
int father[maxn];
int height[maxn]; //点权
int weight[maxn]; //规定顺序假如输入的是 AAA BBB 10,那么A的边权+10,B的边权不加。这样防止重复加边权,而且可以直接通过遍历得到边权。
struct r{ //记录结果result
int people,value;
};
map<string,r> res;//用于输出时候的顺序
map<string,int> finalres;
map<string,int> stringToInt;//形成字符串转int的映射
map<int,string> intToString;//形成int转字符串的映射
int index;//映射函数对应的下标。也是所有的人数
void init(){
res.clear();
stringToInt.clear();
intToString.clear();
finalres.clear();
for(int i=0;i<maxn;i++){
father[i]=i;
height[i]=0;
weight[i]=0;
}
index=0;
}
int change(string str){//映射函数
if(stringToInt.find(str)!=stringToInt.end())
return stringToInt[str];
stringToInt[str]=index;//形成双向映射
intToString[index]=str;
return index++;
}
int find(int x){
if(father[x]!=x)
father[x]=find(father[x]);
return father[x];
}
void Union(int x,int y){ //weight点权最大的当头节点,可能会有子节点的点权大于父节点的情况
int headx,heady;
int fx=find(x);
int fy=find(y);
headx=fx;heady=fy;
if(height[x]>height[fx]){ //判断子节点和父节点的情况,始终让 父节点的点权最大
father[fx]=x;
father[x]=x;
headx=x;
}
if(height[y]>height[fy]){
father[fy]=y;
father[y]=y;
heady=y;
}
if(height[headx]>=height[heady])
father[heady]=headx;
else if(height[headx]<height[heady])
father[headx]=heady;
}
int main()
{
int n,k;
while(cin>>n>>k){
init();
int x,y,w;string s1,s2;
for(int i=0;i<n;i++){
cin>>s1>>s2>>w;
x=change(s1);
y=change(s2);
weight[x]+=w;
height[x]+=w;
height[y]+=w;
Union(x,y);
}
for(int i=0;i<index;i++){
find(i);//所有路径都压缩一次,最后变成只有一个根的树
res[intToString[father[i]]].people++;
res[intToString[father[i]]].value+=weight[i];
}int sum=0;
for(auto it=res.begin();it!=res.end();it++){
if(it->second.people>2&&it->second.value>k) {
finalres[it->first]=it->second.people;
sum++;
}
}
cout<<sum<<endl;
for(auto it=finalres.begin();it!=finalres.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
}
return 0;
}


京公网安备 11010502036488号