*PAT_甲级_1034 Head of a Gang (30分) (C++)【图的遍历/DFS】
原创
©著作权归作者所有:来自51CTO博客作者再见萤火虫IT的原创作品,请联系作者获取转载授权,否则将追究法律责任
目录
1,题目描述
题目大意
输入
输出
2,思路
数据结构
自定义函数
注意
算法
3,代码
1,题目描述
- gang:一帮,一伙(罪犯);
- threthold:门槛; 门口; 阈; 界; 起始点; 开端;
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:
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:
题目大意
判断给出的通话记录中,有几个团伙(三个或三个以上的人,相互联系的时间超过threthold,即判定为团伙),以及团伙中的头目(通话时间最长的人)
输入
- 通话记录数目N(<=1000),判定为团伙的阈值K(<=1000);
- 通话双方名称,通话时间time;
输出
- 团伙的数目;
- 每个团伙的头目,成员个数;
2,思路
这一题参考柳神的思路(一开始因为字符串原因,没法按照以往思路构建图,没想到这里直接将字符串编号,完美解决问题!)
将每条通话记录对应人的名称映射为数字,从而构建图(边权为任意两人通话时长,点权为此人的通话时长)。在此图中使用DFS算法,遍历每个连通分量(每个连通分量相当于一个团伙,当此分量的节点数超过两个,且通话总时长超过阈值,则记录下来)
数据结构
- map<string, int> strToInt:将名称映射为数字;map<int, string> intToStr:将数字映射为名称;
- int graph[2001][2001], weight[2001]:graph边权,存放两人间的通话时长;weight点权,记录个人的通话时长;
- map<string, int> ans:存放每个团伙的头目名称,团伙人数;
自定义函数
- int stoiFunc(string s):将字符串s对应的int型编号输出(接收数据时,便已经为每个人编号了);
- void dfs(int start):递归遍历图中的每一条边;1,进入函数visited[start] = true,先将当前顶点与head的通话时长比较,更新head;2,遍历当前节点相邻的所有边,若边未访问(graph[start][i] == 0),则将此边的权值加在totalTime中;3,若边对应的节点未访问,则以此节点作为入口,递归调用dfs函数;
- void getAns():遍历所有连通分量,得出答案ans;
注意
- 最多1000条通话记录,对应最多2000个人;
- 与普通的DFS遍历不同,此处的DFS需要遍历每一条权值不为0的边,不管边的另一端点是否已经访问过。
- map默认按key进行排序,所以直接一个一个输出即可;
算法
- 接受每条通话记录,为每个人编号,构建图的边权(任意两人的通话时长)和点权(单个人的通话时长);
- 从编号1开始,遍历图,计算每个连通分量(dfs)对应的人数,总通话时长,头目名称;
3,代码
#include<iostream>
#include<vector>
#include<map>
#include<climits>
#include<algorithm>
using namespace std;
int n, k; //n通话记录数目 k阈值
map<string, int> strToInt; //将名称映射为数字
map<int, string> intToStr; //将数字映射为名称
int graph[2001][2001], weight[2001]; //graph边权,存放两人间的通话时长;weight点权,记录个人的通话时长
bool visited[2001]; //1000条记录对应最多2000个人
int curID = 1; //为每个人分配编号(还可以记录人数)
int head = 1, num = 0, totalTime = 0; //head团伙的头目 num团伙的人数 totalTime团队总的通话时长
map<string, int> ans;
int stoiFunc(string s){ //查找字符串对应的数字编号(若存在,返回其编号;不存在,为其分配新编号)
if(strToInt[s] == 0){ //若不存在s,则添加,并且默认初始化为0;
strToInt[s] = curID;
intToStr[curID] = s;
return curID++;
}else
return strToInt[s];
}
void dfs(int start){
visited[start] = true;
num++;
if(weight[start] > weight[head]){
head = start;
}
for(int i = 1; i < curID; i++){
if(graph[start][i] != 0){ //边未访问过
totalTime += graph[start][i];
graph[start][i] = graph[i][start] = 0;//若点访问到了,但边未访问过 会出错(边访问过后置0)
if(visited[i] == false) //边对应的点未访问过
dfs(i);
}
}
}
void getAns(){
for(int i = 1; i < curID; i++){
if(visited[i] == false){
head = i;
num = 0;
totalTime = 0;
dfs(i);
if(num > 2 && totalTime > k){
ans[intToStr[head]] = num;
}
}
}
}
int main(){
//#ifdef ONLINE_JUDGE
//#else
// freopen("1.txt", "r", stdin);
//#endif
cin>>n>>k;
string s1, s2;
s1.resize(3);s2.resize(3);
int time;
for(int i = 0; i < n; i++){ //得出每两人 以及每个人的通话时长
scanf("%s %s %d", &s1[0], &s2[0], &time);
int id1 = stoiFunc(s1);
int id2 = stoiFunc(s2);
graph[id1][id2] += time;
graph[id2][id1] += time;
weight[id1] += time;
weight[id2] += time;
}
getAns();
cout<<ans.size()<<endl;
for(auto it = ans.begin(); it != ans.end(); it++){
cout<< it->first <<' '<< it->second << endl;
}
return 0;
}