PAT甲级1034 Head of a Gang (C++)

题意:给出一段通话记录 第一行 几条通话记录 成为犯罪团伙的通话最小时长
后面就是 代号1 代号2 通话时间。
题解:本题难度略大,出了要考虑是深搜以外,还需要考虑数据的存储问题,需要将字符与编号相互转换,整体思路就是将整个通话记录构建一张图,这个图当然是利用编号作为节点进行构建,然后再看连通子图是否满足其犯罪团伙的条件,满足还要记得排序 然后输出
共多少团伙
团伙头目 团伙共几人
如果没有团伙,输出0即可。
详细代码样例:

#include <bits/stdc++.h>
using namespace std;
//说白了 构造一个连通子图 只有子图足够大时 才能够判断是犯罪团伙 
int N,K,minute[2001] = {0},visited[2001] = {0};//minute是通话次数  
unordered_map<string,int> M1;//实现字符与编号的转换 
unordered_map<int,string> M2;//为了找距离 
vector <int> v[2001];//保证连接关系 
struct gang{//构成有成员 有头领 有通话总时间 
    vector<int>member;
    string head;
    int totaltime;
};//团伙结构体
gang g[2001];
int num_of_gang = 0;
void dfs(int cur){
    if(visited[cur]) return;//及时止损
    visited[cur]=1;//遍历过后标记 
    g[num_of_gang].member.emplace_back(cur);//把这个点加进去 
    g[num_of_gang].totaltime+=minute[cur];//当前这个团队的总时间 
    for(int each:v[cur]){//然后开始遍历与这个点有关的所有节点 来构建一张连通子图 
        dfs(each);
    }
}
//因为团队要按照首领的字母大小排序 
bool comp(gang x,gang y){
    return x.head<y.head;
}
int main(){
    int i,j,k,l;
    cin>>N>>K;
    for(i=0;i<N;i++){
        string s1,s2;
        cin>>s1>>s2>>l;
        //字符串不方便定位,转为数字
        if(M1.count(s1)) j = M1[s1];//如果M1有这个名字 那么把这个人的代号拿出来 给以后的通话次数+1 
        else{
            j = M1[s1] = M1.size()+1;//如果没有的话 就新开一个编号 原有的尺寸+1 
            M2[j] = s1;//M2就是实现数字转换到字符串 
        }
        //下面是第二个人  
        if(M1.count(s2)) k = M1[s2];
        else{
            k=M1[s2] = M1.size()+1;
            M2[k] = s2;
        }
        minute[j]+=l;//该行的j编号的通话次数 
        minute[k]+=l;//改行的k编号的通话次数 
        v[j].emplace_back(k);//j与k相互连接咯 
        v[k].emplace_back(j);
    }
    for(i=0;i<=M1.size();i++){//开始遍历连通子图 每个点都遍历 然后遍历过的就不遍历啦 看看有多少个连通子图 每个子图是否满足gang 如果满足就记录下来咯 
    if(!visited[i]){//该点未遍历过 
        g[num_of_gang].member.clear();//gang的初始化 
        g[num_of_gang].totaltime=0;//时间初始化 这些是不是不用吧 不是的 嘿嘿嘿 这个还必须要 因为 可能if压根就不满足 那个这个团队其实是废了的 重新要做一个团队 这个还蛮坑的 
        dfs(i);
        //开始处理连通子图里面的点 
        if(g[num_of_gang].member.size()>2&&g[num_of_gang].totaltime>K*2){//首先要满足连通子图的点大于两个人 且时间大于规定时间 
        //开始确定首领的头 
            int maxminute = 0;
            int head;
            //遍历连通子图的每一个点所有的时间 
            for(int each:g[num_of_gang].member){//找团队首领 
                if(minute[each]>maxminute){//找到通话次数最多的那个 首领就找到了 
                    maxminute = minute[each];
                    head=each;
                }
            }
            g[num_of_gang].head=M2[head];//把首领的字符串给到这个团队编号 
            num_of_gang++;//团队编号进入下一个 
        }
    }
    
    }
    //gang排序
    sort(g,g+num_of_gang,comp);
    //输出团队有多少个 
    cout<<num_of_gang<<endl;
    //每个团队的具体信息 比如 头领 成员有多少 
    for(i=0;i<num_of_gang;i++){
        cout<<g[i].head<<' '<<g[i].member.size()<<endl;
    }
}

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值