题目链接:Heap of a gang
题意大概是这样的:给定若干组存在通话的成员,以及通话的时间,这些通话将他们分为若干组,每个组的总边权等于所有通话的长度总和。
现在对于每一个组,如果组内成员人数大于2并且总的通话长度大于给定的一个阈值,就认为这个组是一个团伙,组内通话长度最大的成员就是这个团伙的头目。
输入是若干组数据,输出团伙的个数以及每个团伙的头目和相应的团伙成员数。
并查集的思路大致是这样的:
1、首先将字符串映射为数字编号,可以直接使用stl中的map,我在这里是强行定义一个结构数组(记录成员名、点权),结构体数组的下标就是字符串对应的数字编号。
2、Union操作,这里在合并两个点所属的集合时,总是将点权更大的根结点作为根结点。
3、在统计每个集合的成员数目时需要注意最好写成isRoot[findFather[i]]
而不是isRoot[father[i]]
,否则的话需要在前面执行一遍路径压缩。
4、最后排序的过程中需要注意是从第0个元素开始还是第1个元素开始。
代码尽量用C写的,将就着看吧:)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2010;
struct person
{
char name[4];
int weight;
}per[maxn];
struct edge{
int from;
int to;
}edges[maxn];
struct header
{
char name[4];
int num;
}head[maxn];
int N, k; //n: the number of phone calls; k: the weight threthold
int father[maxn];
int isRoot[maxn];
int sum[maxn] = {0};
bool cmp(header a, header b){
return strcmp(a.name, b.name) < 0;
}
void init(int n){
for(int i = 0; i < n; i++){
father[i] = i;
isRoot[i] = 0;
}
}
//find root and compress
int findFather(int x){
int a = x;
while(x != father[x]){
x = father[x];
}
int r;
while(a != father[a]){
r = father[a];
father[a] = x;
a = r;
}
return x;
}
void Union(int a, int b){
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB){
if(per[faA].weight > per[faB].weight)
father[faB] = faA;
else
father[faA] = faB;
}
}
int main()
{
char nameA[4], nameB[4];
int w;
while(scanf("%d%d", &N, &k) != EOF){
int num = 0; //the number of persons recorded in array:per[maxn]
init(maxn);
for(int i = 1; i <= N; i++){
scanf("%s%s%d", nameA, nameB, &w);
int m = 0, n = 0;
for(m = 0; m < num; m++){
if(strcmp(nameA, per[m].name) == 0){
per[m].weight += w;
break;
}
}
if(m == num){
strcpy(per[m].name, nameA);
per[m].weight = w;
num++;
}
for(n = 0; n < num; n++){
if(strcmp(nameB, per[n].name) == 0){
per[n].weight += w;
break;
}
}
if(n == num){
strcpy(per[n].name, nameB);
per[n].weight = w;
num++;
}
edges[i].from = m;
edges[i].to = n;
}
for(int i = 1; i <= N; i++)
Union(edges[i].from, edges[i].to);
for(int i = 0; i < num; i++){
isRoot[findFather(i)]++;
sum[findFather(i)] += per[i].weight;
}
int ans = 0;
for(int i = 0; i < num; i++){
if(isRoot[i] > 2 && sum[i] > 2 * k){
ans++;
head[ans].num = isRoot[i];
strcpy(head[ans].name, per[i].name);
}
}
printf("%d\n", ans);
if(ans != 0)
sort(head+1, head+1+ans, cmp);
for(int i = 1; i <= ans; i++){
printf("%s %d\n", head[i].name, head[i].num);
}
}
return 0;
}
下面是dfs版本的代码:
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int maxn = 2010;
map<string, int> stringToInt;
map<int, string> intToString;
map<string, int> Gang;
int n, k, numPerson = 0;
bool vis[maxn] = {false};
int G[maxn][maxn] = {0}, weight[maxn] = {0};
int change(string str){
if(stringToInt.find(str) != stringToInt.end()){
return stringToInt[str];
}
else{
stringToInt[str] = numPerson;
intToString[numPerson] = str;
return numPerson++;
}
}
void dfs(int nowVisit, int& head, int& totalValue, int& numMember)
{
numMember++;
vis[nowVisit] = true;
if(weight[nowVisit] > weight[head]){
head = nowVisit;
}
totalValue += weight[nowVisit];
for(int i = 0; i < numPerson; i++){
if(G[nowVisit][i] > 0){
// totalValue += G[nowVisit][i];
// G[nowVisit][i] = G[i][nowVisit] = 0;
if(vis[i] == false){
dfs(i, head, totalValue, numMember);
}
}
}
}
void dfsTrave()
{
for(int i = 0; i < numPerson; i++){
int head = i, totalValue = 0, numMember = 0;
if(vis[i] == false){
dfs(i, head, totalValue, numMember);
if(totalValue > k && numMember > 2){
Gang[intToString[head]] = numMember;
cout << totalValue/2 << endl;
}
}
}
}
int main()
{
int w;
string str1, str2;
cin >> n >> k;
for(int i = 0; i < n; i++){
cin >> str1 >> str2 >> w;
int id1 = change(str1);
int id2 = change(str2);
weight[id1] += w;
weight[id2] += w;
G[id1][id2] += w;
G[id2][id1] += w;
}
dfsTrave();
cout << Gang.size() << endl;
map<string, int>::iterator it;
for(it = Gang.begin(); it != Gang.end(); it++){
cout << it->first << " " << it->second << endl;
}
return 0;
}