返回目录
题意
给出若干人之间的通话长度(视为无向边),按照这些通话将他们分为若干个组。每个组的总边权设为该组内的所有通话的长度之和,而每个人的点权设为该人参与的通话长度之和。现在给定一个阈值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
注意点
- 本题使用邻接矩阵存储通话记录图,如果使用邻接表会相当麻烦。
- 除了使用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;
}