1. 程式人生 > >並查集模擬_1034 Head of a Gang (30 分)

並查集模擬_1034 Head of a Gang (30 分)

1034 Head of a Gang (30 分)

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.

Input Specification:

Each input file contains one test case. 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.

Output Specification:

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.

Sample Input 1:

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

Sample Output 1:

2
AAA 3
GGG 3

Sample Input 2:

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

Sample Output 2:

0

 題目中要求找出總聯絡時間大於k,並且聯絡的圈子人數大於2人的圈子,輸出圈子中聯絡時間最長的人以及圈子的人數,按照圈子人數聯絡時間最長的人姓名排序

首先可以想到,將相互聯絡的人建成一棵樹,並且聯絡時間最長的要放在樹根,那麼最簡單的就是使用並查集來實現了,只能實現離線操作,因為如果是線上操作,整棵樹上可以找到相應樹的父親節點,但是找不到當前節點的兒子節點,無法更新根部(聯絡時間最長的節點),

儘量將聯絡時間長的人放在根部,那麼他可以在Union函式中實現,即判斷兩個節點的大小關係,在更新per函式即可,實現還算是比較簡單的,只是有種樣例考慮了很久

3 50
aa bb 20
bb cc 20
cc dd 20

這種情況下,aa節點權值為40,bb權值40,cc權值40,所以最後到底是輸出aa、bb、還是cc呢?我的程式輸出是cc,測試樣例中應該是沒有這種樣例,因為總是感覺輸出aa會比較好一些

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <cmath>
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
const int maxn = 2010;
int per[maxn],num[maxn];
map<string,int> names;
queue<pair<string,string> > que;
string _next[maxn];

int n,k;
struct people
{
    string name;
    int lenth;
}peo[maxn];


void Init()
{
    for(int i = 1;i <= 2*n;i ++) per[i] = i;
}
int Find(int x)
{
    return  x == per[x] ? x:per[x] = Find(per[x]);
}

void Union(int x,int y)
{
    x = Find(x);
    y = Find(y);
    if(x != y)
    {
        if(peo[x].lenth > peo[y].lenth)
            per[y] = x;
        else
            per[x] = y;
    }
}

int main()
{
    scanf("%d%d",&n,&k);
    Init();
    getchar();
    string name1,name2;
    int len,index = 0;
    for(int i = 1;i <= n;i ++)
    {
        cin>>name1>>name2>>len;
        if(!names[name1]){
            names[name1] = ++index;
            peo[index].name = name1;
            peo[index].lenth = len;
        }
        else
            peo[names[name1]].lenth += len;
        if(!names[name2]){
            names[name2] = ++index;
            peo[index].name = name2;
            peo[index].lenth = len;
        }
        else
            peo[names[name2]].lenth += len;
        que.push(make_pair(name1,name2));
    }
//    for(int i = 1;i <= index;i ++)
//        cout << peo[i].name<<" "<<peo[i].lenth<<endl;
    pair<string,string> p;
    while(!que.empty())
    {
        p = que.front();que.pop();
        Union(names[p.first],names[p.second]);
    }
    for(int i = 1;i <= index;i ++)
    {
        int x = Find(i);
        if(per[i] != i)
            peo[x].lenth += peo[i].lenth;
        num[x] ++;
    }
//    for(int i = 1;i <= index;i ++)
//        cout << peo[i].name<<" "<<peo[i].lenth<<endl;

    int pos = 0;
    for(int i = 1;i <= index;i ++)
    {
        if(num[i] > 2 && peo[i].lenth > k*2)
            _next[++pos] = peo[i].name;
    }
    if(pos == 0)
        printf("0\n");
    else{
        printf("%d\n",pos);
        sort(_next+1,_next+pos+1,less<string>());
        for(int i = 1;i <= pos;i ++)
            cout << _next[i] << " "<<num[names[_next[i]]]<<endl;
    }
}