Head of a Gang

Head of a Gang

http://www.nowcoder.com/questionTerminal/a31b1ea6c87647bc86e382acaf21c53b

我使用的并查集
name1,name2,time;
思路:用并查集将name1,name2合并,同时每个连通子图的根,负责记录本连通子图的总权重、总成员数量-----(于是我修改了Union函数),这里分为2种情况
(1)name1,name2所在的连通子图不是同一个(即需要合并)
合并之后的本连通子图的总权重=name1所在连通子图根节点的总权重+name2所在连通子图根节点的总权重+两个子图之间的权值
*(2)name1,name2所在的连通子图是同一个(即不需要合并,也就是存在A给B通信,B又给A 通信的这种双向通信情况) *
本连通子图的总权重=本连通子图的总权重+新增权值

个人权重:
例如 x,y,w1; y,z,w2;这两条记录 那么weight_of_each_one[y]=w1+w2;

每次找到团伙之后遍历所有人,找属于该团伙的成员,并寻找头目(即个人权重最大的)
代码tips:

  • 整个代码处理过程中全部用的int类型 只在输入和输出的部分做了int与string的转换
  • map可以保证最后的结果按字典顺序输出
#include<iostream>
#include<cstdio>
#include<string>
#include<map>

using namespace std;

const int MAX=26;
int father[MAX];
int height[MAX];
int number_of_each_gang[MAX];
int weight_of_each_gang[MAX];
int weight_of_each_one[MAX];
bool visited[MAX];

int ToDigit(string str) {
    return str[0]-'A';
}
string ToString(int x) {
    string ans="";
    //for(int i=0; i<3; i++) {
        ans+=x+'A';
//    }
    return ans;
}
void Init() {
    for(int i=0; i<MAX; i++) {
        father[i]=i;
        height[i]=0;
        number_of_each_gang[i]=1;//刚开始是自己一个人 
        weight_of_each_gang[i]=0;
        visited[i]=false;
        weight_of_each_one[i]=0;
    }
}
int Find(int x) {
    if(x!=father[x]) {
        father[x]=Find(father[x]);
    }
    return father[x];
}
void Union(int x,int y,int weight) {
    x=Find(x);
    y=Find(y);
    if(x!=y) { //不属于同一连通子图
        if(height[x]<height[y]) {//y是根
            father[x]=y;
            weight_of_each_gang[y]+=weight+weight_of_each_gang[x];//两个子图合并加上中间的连接权值 
            number_of_each_gang[y]+=number_of_each_gang[x];//两个子图人员合并
        } else if(height[x]>height[y]) { //x是根
            father[y]=x;
            weight_of_each_gang[x]+=weight+weight_of_each_gang[y];
            number_of_each_gang[x]+=number_of_each_gang[y];
        } else { //x是根
            father[y]=x;
            height[x]++;
            weight_of_each_gang[x]+=weight+weight_of_each_gang[y];
            number_of_each_gang[x]+=number_of_each_gang[y];
        }
    } else { //已经属于同一连通子图 (权值增加  人数不增加)
        weight_of_each_gang[x]+=weight;
    }
}

int main() {

    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF) {
        Init();
        while(n--) {
            string Name1, Name2;
            int Time;
            cin>>Name1>>Name2>>Time;

            int N1=ToDigit(Name1);
            int N2=ToDigit(Name2);
            visited[N1]=true;
            visited[N2]=true;
            weight_of_each_one[N1]+=Time;//个人权值
            weight_of_each_one[N2]+=Time;
            Union(N1,N2,Time);
        }
        int number_of_gang=0;
        map<int,int> head;
        for(int i=0; i<MAX; i++) {
            if(!visited[i]) {
                continue;
            }            
            if(father[i]==i&&number_of_each_gang[i]>2&&weight_of_each_gang[i]>k) { //符合gangs定义
                    number_of_gang++;
                int ID=i;//记录头目的编号(初始化为这个团伙的根成员的编号)
                int max_weight=weight_of_each_one[i];//记录头目的权值(初始化为这个团伙的根成员的权值)
                for(int j=0; j<MAX; j++) {
                    if(!visited[i]||i==j) {
                        continue;
                    }
                    if(Find(j)==i) { //找到属于这个gang的成员
                        if(max_weight<weight_of_each_one[j]) {
                            ID=j;
                            max_weight=weight_of_each_one[j];
                        }
                    }
                }
                head[ID]=number_of_each_gang[i];
            }
        }

        cout<<number_of_gang<<endl;
        if(number_of_gang!=0) {
            map<int,int>::iterator it;
            for(it=head.begin(); it!=head.end(); it++) {
                cout<<ToString(it->first)<<" "<<it->second<<endl;
            }
        }
    }
    return 0;
}
全部评论

相关推荐

挣K存W养DOG:他真的很中意你,为什么不回他
点赞 评论 收藏
分享
ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务