1034 Head of a Gang (30 分)
One way that the police finds the head of a gang is to check people’s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A “Gang” is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threthold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threthold, respectively. Then N lines follow, each in the following format:
Name1 Name2 Time
where Name1
and Name2
are the names of people at the two ends of the call, and Time
is the length of the call. A name is a string of three capital letters chosen from A
–Z
. A time length is a positive integer which is no more than 1000 minutes.
Output Specification:
For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.
Sample Input 1:
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
Sample Output 1:
2
AAA 3
GGG 3
Sample Input 2:
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
Sample Output 2:
0
题目要求:
根据每个人之间的通话时长来确定一个帮派的头目和成员个数。给出N个电话记录(N不超过1000)以及最小帮派通话时长K ,每个通话记录有打电话者姓名、接电话者姓名以及通话时长(分钟)。姓名用3个大写字母表示。通话时长不超过1000。两个人之间打电话就认为他们之间有关联。当关联人数超过2人以及通话时长超过给定的K,就认为这是一个帮派,其中通话时间最长的就是头目。最后输出帮派的数量以及每个帮派头目的名称和帮派中成员个数。输出结果按字母表顺序排序。每个帮派的头目唯一。
解题思路:
利用dfs可以遍历图确定连通分量,这里一个连通分量也就相当于一个帮派。然而姓名为三个字母,难以用下标表示,所以用map映射,将姓名映射成对应的下标map1。这里还需要有一个从下标映射回姓名的map2。因为最后输出的结果还是姓名。如果不用这个map2的话,需要将之前map1进行遍历一遍,才能根据下标找到姓名,十分耗时。这里要注意map在按key找value时,如果找到了返回value,如果没找到则返回0
接下来就是正常的dfs。在一次连通的dfs的过程中要统计帮派的总权重(即通话时长)以及帮派成员的个数还有帮派的头目下标。
由于在初始化的时候就将每个通话记录的权重分布加到了对于两个成员的身上,所以每次到一个成员的时候直接把成员所具有的权重加到总权重里就好了,最后的总权重实际上是两倍的实际权重值。
帮派成员数量就根据一次连通的dfs所能到达的成员数
头目下标,每次比较当前成员的权重是否大于最大的权重值,大于就暂且认为他是头目
每次连通的dfs遍历后,判断成员个数是否大于2,总权重是否大于2*K
最后将所有帮派按照字典序排序后输出
注意:
1.最后的输出结果按字典序排序,之前没看到这条,测试点2和5始终通不过,找了一个小时错误
2.初始化的时候要注意A打给B,要对数组[A][B]以及[B][A]都要赋值,这是一个无向图
完整代码:
#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxsize 2005
struct Gang{
string head;
int num;
};
/*将帮派头目按字典序排序*/
bool comp(Gang gang1,Gang gang2){
return gang1.head < gang2.head;
}
Gang gang[maxsize]; //帮派信息
map<string,int > m1; //stingToint;
map<int,string > m2; //intTosting;
int a[maxsize][maxsize]; //边的权值
int weight[maxsize]; //节点的权值
int visit[maxsize];
int N,K;
int num=1; //下一插入map中的下标
int totalweight=0,totalnum=0; //每个帮派的总权重以及成员数
int maxweight = 0,maxid = 0; //每个帮派最大的权值成员和它的下标
int gangnum=0;
void dfs(int v){
int i;
visit[v] = 1;
totalnum += 1;
totalweight += weight[v];
if(weight[v] > maxweight){
maxweight = weight[v];
maxid = v;
}
for(i=1;i<num;i++){
if(a[v][i]>0 && visit[i]==0){
dfs(i);
}
}
}
void dfstraversal(){
int i;
for(i=1;i<num;i++){
totalweight=0;totalnum=0;
maxweight=0;maxid=0;
if(visit[i] == 0){
dfs(i);
}
if(totalnum > 2 && totalweight > 2*K){
gangnum++;
gang[gangnum].head = m2[maxid];
gang[gangnum].num = totalnum;
}
}
cout<<gangnum<<endl;
sort(gang+1,gang+gangnum+1,comp);
for(i=1;i<=gangnum;i++){
cout<<gang[i].head<<" "<<gang[i].num<<endl;
}
}
int main(){
string s1,s2;
int i,j,k,time,l,r;
memset(a,0,sizeof(a));
memset(visit,0,sizeof(visit));
cin>>N>>K;
for(i=1;i<=N;i++){
cin>>s1>>s2>>time;
l = m1[s1];
r = m1[s2];
if(l == 0){
m1[s1] = num;
m2[num] = s1;
l=num;
num++;
}
if(r == 0){
m1[s2] = num;
m2[num] = s2;
r=num;
num++;
}
a[l][r]+=time;
a[r][l]+=time;
weight[l]+=time;
weight[r]+=time;
}
dfstraversal();
}