九度 题目1446:Head of a Gang

九度 题目1446:Head of a Gang

原题OJ链接:http://ac.jobdu.com/problem.php?pid=1446

题目描述:

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.

输入:

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.

输出:

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.

样例输入:

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
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

样例输出:

2
AAA 3
GGG 3
0

解题思路:

题目意思:每组首先输入边的个数 N 和一个阈值 K。接下来输入每一条边的信息,两个结点 A, B,然后是这条边的权重Time。两个结点的名字必须是三个大写英文字母组成,所以在代码中使用了STL中的map映射,将每一个结点的英文字符串映射到一个独一无二的数字结点。
在这个图中,寻找连通分量,该连通分量中权重之和大于阈值K,且所包含结点个数大于2。
输出:第一行是满足上述条件连通分量的个数,第二行之后每一行输出每一个连通分量中 最大的结点(该结点与其他结点相连的权重之和最大)名称和该连通分量中结点个数。

源代码:

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
#define MAX_N 1005
int Tree[MAX_N];
int sum[MAX_N]; 
/*记录每一个结点的权重和,把一个并查集合中权重之和存储到根结点上,
若结点 i 为根结点,则sum[i]为该并查集合中的边的权重之和*/

int member[MAX_N];
/*记录所在并查集合中结点个数,存储在根结点上
若结点 i 为根结点,则member[i]为该并查集合中结点个数*/

string ans[MAX_N]; //与map相反映射
map <string,int> Map;// Map["AAA"]=1,ans[1]="AAA"; 
map <string,int>::iterator iter;

int gangRoot[MAX_N][2];
/*gangRoot[i][0]存储每一个cluster中的根结点,
gangRoot[i][1]存储该cluster中结点个数
*/

int value[MAX_N];//记录每个结点的time
/*例如样例一中,把AAA,BBB,CCC分别映射为结点1,2,3
则value[1]=70,value[2]=30,value[3]=40*/


struct POS{
    string str;
    int num;
} pos[MAX_N];
/*该结构体数组存储每一个cluster中的head,
string类型的结点名字和该结点所在cluster中的结点个数num
*/

bool cmp(POS a,POS b){
    return a.str<b.str;
}//sort()函数中的比较函数,即输出head结点按字母表排序

int findRoot(int x){//寻找根结点
    if(Tree[x]==-1) return x;
    else{
        int tmp=findRoot(Tree[x]);
        Tree[x]=tmp;
        return tmp;
    }
}

int main(){
    int N,K,time;
    string name1,name2;
    while(cin>>N>>K){
        for(int i=0;i<MAX_N;i++){
            Tree[i]=-1;
            sum[i]=0;
            member[i]=1;
            ans[i]="";
            value[i]=0;
        }
        for(iter=Map.begin();iter!=Map.end();iter++){
            iter->second=0;
        }//遍历map,将所有节点初始化为0

        int node=1;//将字母结点转化为数字结点,一一对应,从结点1开始
        for(int i=0;i<N;i++){
            cin>>name1>>name2>>time;
            if(Map[name1]==0){
                Map[name1]=node;//映射,字符——>数字
                ans[node]=name1;//映射,数字——>字符
                node++;
            }
            if(Map[name2]==0){
                Map[name2]=node;
                ans[node]=name2;
                node++;
            }


            int a=Map[name1];
            int b=Map[name2];
            value[a]+=time;
            value[b]+=time;

            a=findRoot(a);
            b=findRoot(b);
            if(a!=b){

                Tree[a]=b;
                member[b]+=member[a];
                sum[b]=sum[b]+sum[a]+time;
            }

            else{//若这两个结点已经存在一条边,只是累加权重,成员数保持不变
                sum[a]+=time;
            }           
        }


        int count=0;
        memset(gangRoot,0,sizeof(gangRoot));
        for(int i=1;i<node;i++){
            if(Tree[i]==-1 && sum[i]>K && member[i]>2){
                gangRoot[count][0]=i;
                gangRoot[count][1]=member[i];
                count++;               
            }
        }

        cout<<count<<endl;
        for(int i=0;i<count;i++){
            int tmp=0;            
            pos[i].num=gangRoot[i][1];
            for(int j=1;j<node;j++){
                int c=findRoot(j); 
                if(c==gangRoot[i][0] && value[j]>tmp){
                    tmp=value[j];
                    pos[i].str=ans[j];

                }
            }
        }

        sort(pos,pos+count,cmp);//按字母表排序

        for(int i=0;i<count;i++){
            cout<<pos[i].str<<" "<<pos[i].num<<endl;
        }

    }
    return 0;
}

结果截图:

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值