题目链接:click here
题目大意:如王道书中所言,找团伙头头和他的人数。
思路:这题与其说是并查集,不如说是对字符串的处理。由于将输入的字符串转化为对应点再进行并查集,并查集后再用输出字符串和与其相关的数,所以我这里用了3个map和1个set。。其中还有一个嵌套map,很少这么玩。。
整体思路是这样子:
并查集部分是按节点权重关系合并集合。
1、先将边存入结构体;
2、再将节点编号(此时字符串是按顺序编号的);
3、然后对边遍历,修改节点权值数组;
4、合并,同时进行路径更新;(由于是按照节点权值合并集合,并非按照单边权值合并,所以最后要进行路径压缩更新)
5、从father数组中找出首脑并统计其成员数量;
6、清除假首脑、假团体(团体必须大于2人);
7、输出。
由于没有路径更新1W,前提是牛客给了测试数据。。考试考出来肯定不能这么冷静的做完吧,呵呵。。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <climits>
using namespace std;
const int MAXN = 2005;
const int INF = INT_MAX;
struct Edge{
string SourceA;
string SourceB;
int value;
};
int N, K;
int father[MAXN], weight[MAXN];
Edge edge[MAXN];
int Find(int x){
if(x != father[x]) father[x] = Find(father[x]);
return father[x];
}
void Union(int x, int y){
x = Find(x);
y = Find(y);
if(x != y){
if(weight[x] < weight[y]) father[x] = y;
else if(weight[y] < weight[x]) father[y] = x;
else{//权值相等
if(y < x) father[x] = y;
else if(x < y) father[y] = x;
}
}
}
void Initial(){
for(int i = 0; i < MAXN; i++){
father[i] = i;
weight[i] = 0;
}
}
int main(){
// freopen("in.txt", "r", stdin);
while(~scanf("%d %d", &N, &K)){
Initial();
set<string> allPoint;//所有字符串点
map<string, int> mymap1;//字符串到编号
map<int, string> mymap2;//编号到字符串
map<int, pair<int, int> > mymap3;//编号到次数
for(int i = 0; i < N; i++){
cin >> edge[i].SourceA;
cin >> edge[i].SourceB;
scanf("%d", &edge[i].value);
allPoint.insert(edge[i].SourceA);
allPoint.insert(edge[i].SourceB);
}
//编号
set<string>::iterator it1;
int count = 0; //count为节点数
for(it1 = allPoint.begin(); it1 != allPoint.end(); it1++){
mymap1[*it1] = count;
mymap2[count] = *it1;
count++;
}
//加入边得出权值数组
int num1, num2;
for(int i = 0; i < N; i++){
num1 = mymap1[edge[i].SourceA];
num2 = mymap1[edge[i].SourceB];
weight[num1] += edge[i].value;
weight[num2] += edge[i].value;
}
//对所有边合并
for(int i = 0; i < N; i++){
num1 = mymap1[edge[i].SourceA];
num2 = mymap1[edge[i].SourceB];
Union(num1, num2);
}
//路径更新
for(int i = 0; i < count; i++){
Find(i);
}
//从father数组中找出boss
map<int, pair<int, int> >::iterator it2;
int boss;
for(int i = 0; i < count; i++){
boss = father[i];
it2 = mymap3.find(boss);
if(it2 != mymap3.end()){
mymap3[boss].first++;
mymap3[boss].second += weight[i];
}
else{
mymap3[boss].first = 1;
mymap3[boss].second = weight[i];
}
}
//消除假boss
map<int, pair<int, int> >::iterator it3;
for(it3 = mymap3.begin(); it3 != mymap3.end(); it3++){
if(it3->second.first <= 2 || ((it3->second.second / 2) <= K)) mymap3.erase(it3);
}
//输出
printf("%d\n", mymap3.size());
for(it3 = mymap3.begin(); it3 != mymap3.end(); it3++){
cout << mymap2[it3->first] << " " << it3->second.first << endl;
}
}
return 0;
}