牛客oj 習題11.3 || pat1034 Head of a Gang(帶權值的並查集+嵌套map+set)

 

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章