PTA 1034 Head of a Gang (30 分)

考察知识点:并查集

我使用的数据结构:map、vector

可能的坑点:

1.本来以为每个人的名字是由相同的A-Z之间字母组成(too young too simple T T),然后我没想到用map记录每个名字出现的情况,好的这一次提交就4分

2.知道名字是三个大写英文字母的随机组合,那我不得不用map记录了,然后为了后续好按照名字排序(这也是我没审清题错了好久的点),这一次就14分吧好像

3.记得map中存放的是(名字,对应信息所存放的结构体下标),敲代码的时候注意不能弄乱了

4.电话时间看输入像有向边,其实是无向边,所以我在结构体中设置了weight,用于保存该人的总通话数,记得输入时,要把这个通话时间给双方加上

5.求每个集群老大下标时,要注意每个集群人数>2, 该集群通话时间(就是这个集群所有人电话时间总和/2)>阀值

6.我直接用vector<Person>存每个集群老大的结构体,方便后续按名字排序。

 

感叹PTA无论甲、乙都好细节,确实考验我的耐心...遇到这种30分的题,可能要磕上2小时,才能把细节理清楚,好菜呀呜呜

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
int fa[2010];
struct Person{
    string name;  
    int weight;
    int groupNum;
}person[2010];  //这记得设置成1000*2以上,因为最差的情况每次打电话的双方都是之前没出现过的用户
map<string,int> myMap;
void inital(int n){  //初始化集合
    for(int i=0;i<n;i++){
        fa[i]=i;
    }
}
int Find(int rt){  //找到祖宗
    return fa[rt]==rt?rt:Find(fa[rt]);
}
void Union(int r1,int r2){ //集合合并
    int f1=Find(r1);
    int f2=Find(r2);
    if(f1!=f2){
        fa[f2]=f1;
    }
}
bool cmp(Person p1,Person p2){ //按名字字母顺序排序
    return p1.name<p2.name;
}
int main(void){
    int n,k,index=0;
    scanf("%d %d",&n,&k);
    inital(2*n);
    for(int i=0;i<n;i++){
        string n1,n2;
        int call;
        cin>>n1>>n2>>call;
        if(myMap.count(n1)==0){  //若该用户之前还没出现过就添加进来
            person[index].name=n1;
            person[index].weight+=call;
            myMap[n1]=index++;
        }
        //若该用户出现过,则只用加上其打电话的时间
        else{   
            person[myMap[n1]].weight+=call;
        }
        if(myMap.count(n2)==0){
            person[index].name=n2;
            person[index].weight+=call;
            myMap[n2]=index++;
        }
        else{
            person[myMap[n2]].weight+=call;
        }
        //合并两个用户集合
        Union(myMap[n1],myMap[n2]);
    }
    vector<int> head; //这里面存放的是每个集群其中一个人的下标
    vector<Person> real_head; //存放每个集群老大的信息
//    vector<int> group;
    //找出有几个集群
    for(int i=0;i<index;i++){
        if(fa[i]==i){ 
            head.push_back(i); //存入预备老大的集合
        }
    }
    
    for(int i=0;i<head.size();i++){
        int h=head[i]; //可能的集群老大
        int weight_sum=person[h].weight;
        //记录最大时间 、 最大时间对应下标、集群人数
        int maxx_weight=weight_sum,maxx_index=h,group_num=0;
        for(int j=0;j<index;j++){
            //若该用户属于该集合且不是当前可能的老大
            if(Find(j)==h&&j!=h){
                group_num++;
                weight_sum+=person[j].weight;
                //若当前这个人的总电话数最大,则记录下来,这个过程就是找这个集群老大
                if(maxx_weight<person[j].weight){
                    maxx_weight=person[j].weight;
                    maxx_index=j;
                }
            }
        }
        //若总电话时间(这里除2是因为前面我把之前每对通话记录当作无向边把权重都加上到这个用户的通话时间内,所以/2代表实际该集群总电话数)大于阀值
        if((weight_sum/2)>k&&(group_num+1)>2){
            person[maxx_index].groupNum=group_num+1;
            real_head.push_back(person[maxx_index]);
        }
    }
    //对每个集群老大按名字排序
    sort(real_head.begin(),real_head.end(),cmp);
    printf("%d\n",real_head.size());
    for(int i=0;i<real_head.size();i++){
        cout<<real_head[i].name<<" "<<real_head[i].groupNum<<endl;
    }
//     cout<<count<<endl;
    return 0;
}

 

posted @ 2022-03-18 19:14  一只很皮的猴猴  阅读(19)  评论(0编辑  收藏  举报