牛客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;
}
发布了411 篇原创文章 · 获赞 72 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/Flynn_curry/article/details/105441791