牛客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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
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 allPoint;//所有字符串点 
		map mymap1;//字符串到编号 
		map mymap2;//编号到字符串 
		map > 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::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 >::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 >::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;
}

 

你可能感兴趣的:(王道相关练习,图论-并查集,其他oj,并查集,set,map,权值,牛客)