題目鏈接: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;
}