*PAT_甲级_1034 Head of a Gang (30分) (C++)【图的遍历/DFS】

目录

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:

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

题目大意

判断给出的通话记录中,有几个团伙(三个或三个以上的人,相互联系的时间超过threthold,即判定为团伙),以及团伙中的头目(通话时间最长的人)

输入

  1. 通话记录数目N(<=1000),判定为团伙的阈值K(<=1000);
  2. 通话双方名称,通话时间time;

输出

  1. 团伙的数目;
  2. 每个团伙的头目,成员个数;

 

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. 接受每条通话记录,为每个人编号,构建图的边权(任意两人的通话时长)和点权(单个人的通话时长);
  2. 从编号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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值