PAT甲级 1034 Head of a Gang DFS找连通分量

23 篇文章 0 订阅
22 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Solution:

  • 题目要求:根据每个人之间的通话时长来确定一个帮派的头目和成员个数。
  • 输入:给出N个电话记录(N<=1000)以及最小帮派通话时长K(K<=1000),每个通话记录有打电话者姓名name1、接电话者姓名name2以及通话时长Time(分钟)。姓名用3个大写字母表示。两个人之间打电话就认为他们之间有关联。当关联人数超过2人以及通话时长超过给定的K,就认为这是一个帮派,其中通话时间最长的就是头目。
  • 输出:输出帮派的数量以及每个帮派头目的名称和帮派中成员个数。输出结果按字母表顺序排序。
  • 利用dfs可以遍历图确定连通分量,这里一个连通分量也就相当于一个帮派。然而姓名为三个字母,难以用下标表示,所以用map映射,将姓名映射成对应的下标map1。这里还需要有一个从下标映射回姓名的map2。因为最后输出的结果还是姓名。如果不用这个map2的话,需要将之前map1进行遍历一遍,才能根据下标找到姓名,十分耗时。这里要注意map在按key找value时,如果找到了就返回value,如果没找到则返回0,接下来就是正常的dfs。在一次连通的dfs的过程中要统计帮派的总权重(即通话时长)以及帮派成员的个数还有帮派的头目下标。由于在初始化的时候就将每个通话记录的权重分布加到了对于两个成员的身上,所以每次到一个成员的时候直接把成员所具有的权重加到总权重里就好了,最后的总权重实际上是两倍的实际权重值。帮派成员数量就根据一次连通的dfs所能到达的成员数头目下标,每次比较当前成员的权重是否大于最大的权重值,大于就暂且认为他是头目。每次连通的dfs遍历后,判断成员个数是否大于2,总权重是否大于2*K。最后将所有帮派按照字典序排序后输出。

代码如下:

#include<iostream>
#include<map>
#include<string>
#include<algorithm>
#define MAX 2005
using namespace std;

struct Gang{//帮派
    string head;//帮派的头目
    int num;//帮派成员数
}gang[MAX];

bool cmp(Gang a,Gang b){//帮派按头目名字字典序排序
    return a.head<b.head;
}

map<string,int> m1;
map<int,string> m2;
int mp[MAX][MAX];//边的权值
int weight[MAX];//结点的权值
int visit[MAX];//访问数组
int n,k;//n个结点和阈值k
int totalweight=0,totalnum=0;//每个帮派的总权重以及总成员数量
int maxweight=0,maxid=0;//每个帮派结点的最大权重以及结点编号
int gangnum=0;//帮派数量
int num=1;//记录结点数量

void dfs(int v){
    visit[v]=1;
    totalnum++;
    totalweight+=weight[v];
    if(weight[v]>maxweight){
        maxweight=weight[v];
        maxid=v;
    }
    for(int i=1;i<num;i++){
        if(mp[v][i]>0&&visit[i]==0){
            dfs(i);
        }
    }
}

void dfstraversal(){
    for(int 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,cmp);//排序
	for(int i=1;i<=gangnum;i++){//输出信息
		cout<<gang[i].head<<" "<<gang[i].num<<endl;
	}
}

int main(){
    string s1,s2;
    int a,b,time;
    for(int i=0;i<MAX;i++){//初始化
        visit[i]=0;
    }
    for(int i=0;i<MAX;i++){//初始化
        for(int j=0;j<MAX;j++){
            mp[i][j]=mp[j][i]=0;
        }
    }
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>s1>>s2>>time;
        a=m1[s1];
        b=m1[s2];
        if(a==0){
            m1[s1]=num;
            m2[num]=s1;
            a=num;
            num++;
        }
        if(b==0){
            m1[s2]=num;
            m2[num]=s2;
            b=num;
            num++;
        }
        weight[a]+=time;
        weight[b]+=time;
        mp[a][b]+=time;
        mp[b][a]+=time;
    }
    dfstraversal();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值