PAT.A1034 Head of a Gang

返回目录在这里插入图片描述

题意

给出若干人之间的通话长度(视为无向边),按照这些通话将他们分为若干个组。每个组的总边权设为该组内的所有通话的长度之和,而每个人的点权设为该人参与的通话长度之和。现在给定一个阈值K,且只要一个组的总边权超过K,并满足成员人数超过2,则将该组视为“犯罪团伙(Gang)”,而该组内点权最大的人视为头目。要求输出“犯罪团伙”的个数,并按头目姓名字典序从小到大的顺序输出每个“犯罪团伙”的头目姓名和成员人数。

样例(可复制)

8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
//output
2
AAA 3
GGG 3
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
//output
0

注意点

  1. 本题使用邻接矩阵存储通话记录图,如果使用邻接表会相当麻烦。
  2. 除了使用DFS遍历外,还可以使用并查集的方式解决本题,但相对麻烦些。在并查集合并时,记得需要保持全值最大的节点作为根节点。
#include <bits/stdc++.h>
using namespace std;

const int maxn=2010;
int n,k,num=0;//总通话记录数,阈值,总人数 
map<string,int> stringint;//姓名->编号
map<int,string> intstring;//编号->姓名
map<string,int> gang;//黑帮头目--黑帮人数 
int G[maxn][maxn]={0};//通话记录图,邻接矩阵存储 
int W[maxn] ={0};//每个人的权重 
bool flag[maxn]={false};
int change(string s){
	if(stringint.find(s)!=stringint.end()){
		return stringint[s];
	}else{
		stringint[s]=num;
		intstring[num]=s;
		return num++;
	}
}
void DFS(int now,int& head,int& numperson,int& totalw){
	flag[now]=true;
	numperson++;
	if(W[now]>W[head])head=now;
	for(int i=0;i<num;i++){
		if(G[now][i]>0){
			totalw+=G[now][i];
			G[now][i]=G[i][now]=0;//删除该边,防止回头
			if(!flag[i])DFS(i,head,numperson,totalw);
		}
	}
}
int main(){
    int w;
    string s1,s2;
	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>s1>>s2>>w;
		int id1=change(s1);
		int id2=change(s2);
		W[id1]+=w;
		W[id2]+=w;
		G[id1][id2]+=w;
		G[id2][id1]+=w;
	}
	for(int i=0;i<num;i++){
		if(!flag[i]){
			int head=i,numperson=0,total=0;
			DFS(i,head,numperson,total);
			if(numperson>2&&total>k)gang[intstring[head]]=numperson;
		}
	}
	cout<<gang.size()<<endl;
	for(map<string,int>::iterator it=gang.begin();it!=gang.end();it++){
		cout<<it->first<<" "<<it->second<<endl;
	}
	return 0;
}
发布了177 篇原创文章 · 获赞 5 · 访问量 6655

猜你喜欢

转载自blog.csdn.net/a1920993165/article/details/105559503