PAT1034 Head of a Gang (30)(并查集)

题意:

给出n次通话记录,当通话的人数超过2人并且通话总时长超过k时,这些人就是犯罪团伙,其中通话时间最大的人是头目,要求按字母序输出头目和团伙人数

思路:

就是并查集,将两两通话的人关联在一起,因为通话的人的姓名是按三位字母给出的,所以要离散化,并且对应要用一些STL保存映射。我自己写的时候有两个点没过,后来改过了,错误原因写在下面注释里了。网上的代码也有用DFS找连通分量做的。

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int INF = 0xfffff;
const int maxn = 2010;	//这里开1005会出现段错误,因为是n个通话可能有2n个人

map<string, int> gang;
map<int, string> gangName;
int gangTime[maxn];
int p[maxn];
int n, k,pos=0;
vector<int> head[maxn];
set<string> res;

void init() {
	for (int i = 0; i < maxn; i++) {
		p[i] = i;
		head[i].push_back(i);
	}
}

int find(int x) {
	if (x == p[x]) return x;
	return p[x] = find(p[x]);
}

void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		p[x] = y;
		for (auto i = head[x].begin(); i != head[x].end(); i++) {
			head[y].push_back(*i);
		}
		head[x].clear();		//这里必须清零
	}
}

int main() {
	scanf("%d%d", &n, &k);
	init();
	for (int i = 0; i < n; i++) {
		string name1, name2;
		int time;
		cin >> name1 >> name2 >> time;
		if (gang.find(name1) == gang.end()) {
			gang[name1] = pos;
			gangName[pos++] = name1;
		}
		if (gang.find(name2) == gang.end()) {
			gang[name2] = pos;
			gangName[pos++] = name2;
		}
		gangTime[gang[name1]] += time;
		gangTime[gang[name2]] += time;
		merge(gang[name1], gang[name2]);
	}
	for (int i = 0; i < pos; i++) {
		if (head[i].size() > 2) {
			int maxTime = -1, index;
			int totalTime = 0;
			for (auto x : head[i]) {
				if (maxTime < gangTime[x]) {
					maxTime = gangTime[x];
					index = x;
				}
				totalTime += gangTime[x];
			}
			if (totalTime > 2*k) {
				res.insert(gangName[index]);
			}
		}
	}
	if (res.empty())
		cout << 0 << endl;
	else {
		cout << res.size() << endl;
		for (auto x : res) {
			int h = find(gang[x]);
			cout << x << " " << head[h].size() << endl;
		}
	}
	return 0;
}

 

posted @ 2018-04-18 22:32  seasonal  阅读(83)  评论(0编辑  收藏  举报