1. 程式人生 > >PAT 1034 Head of a Gang

PAT 1034 Head of a Gang

 

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

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

const int M = 10005;

struct inode
{
    //next:下一條鄰接邊
    //to:本條邊所指向的終點
    //l: 權值
    int next,to,l;
}e[M];

int sum = 0;//sum用來記錄 一個部分連通圖的總路徑長度

int weight[M] = {0};//weight記錄每一個點 所連線其他點的路徑總權值
int memeber = 0;//記錄

bool vis[M] = {false};//記錄某個的是否被訪問過

//ihead:鄰接表的頭
//cnt:鄰接表大小
int cnt = 0;
int ihead[M] = {0};

//鄰接表連邊,表示連一條x到y的有向邊
//x:起點
//y:終點
void add(int x,int y,int lon){
    //做標誌
    int w = 0;
    //存在鄰接表節點則路徑值相加 否則加入鄰接表節點
    //遍歷
    for(int i = ihead[x];i != 0;i = e[i].next){
        if(y == e[i].to){
            e[i].l += lon;
            w = 1;
            break;
        }
    }
    //之前 無
    if(w == 0){
        ++cnt;
        e[cnt].next = ihead[x];//下一個鄰接點 就是之前的頭
        e[cnt].to = y;
        e[cnt].l = lon;
        ihead[x] = cnt;//鄰接鏈的頭接點
    }
}

//操作相加每個點所連線所有點的總權值
int SumW(int N){
    for(int i = 1;i <= N;i++){
        for(int j = ihead[i];j != 0;j = e[j].next){
            weight[i] += e[j].l;
        }
    }
}

//深度優先搜尋
int DFS(int u,int depth){

    vis[u] = true;//設定u已經被訪問
    sum += weight[u];//圖中每一個點的所連線其它點的總權值
    ++memeber;//記錄節點總數
    // 遍歷e[i]
    for(int i = ihead[u];i != 0;i = e[i].next){

        if(vis[e[i].to] == false){
            //printf(" -> %d",e[i].to);
            DFS(e[i].to,depth + 1);//訪問e[i].to
        }
    }
}
void DFSTraver(int N,int K){

    for(int i = 1;i <= N;i++){
        //sum memeber置0
        sum = 0;
        memeber = 0;
        if(vis[i] == false){//當i點沒有被訪問時

            DFS(i,1);
            sum /= 2;
            if(sum >= K && memeber > 2)
                printf("%d %d %d\n",i,memeber,sum);
        }
    }
}
int main(int argc, char const *argv[]) {

    //N代表總運算元
    //K代表限度總邊權
    int N,K;

    scanf("%d%d",&N,&K);

    for(int i = 1;i <= N;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);

        //兩個add主要是結局 A <-> B、B <->A問題
        add(a,b,c);
        add(b,a,c);
    }

    printf("head memeber time:\n");

    SumW(N);
    DFSTraver(N,K);
    return 0;
}

#include <iostream>
#include <cstdio>
#include <map>
#include <vector>

using namespace std;

const int Mx = 10005;

int weight[Mx] = {0};//weight記錄每個點所連線的所有路徑的權值總和
int imap[Mx][Mx] = {0};//鄰接矩陣
int SumMember = 0;//記錄總人數


map<string,int> srtoi;//名稱->下標
map<int,string> itos;//下標->名稱

bool vis[Mx] = {false};//記錄某點是否被訪問過

int head = 0,imax = 0;//用於找出頭目
int aofw = 0;//記錄一個團伙的總通話時間
int atuan = 0;//記錄一個團伙的成員數量

int sumP = 0;//記錄犯罪團伙數量

//vec1 用於記錄head的編號
//vec2 用於記錄團伙的人數
vector<int> vec1;
vector<int> vec2;

void DFS(int u) {
    //標誌已經被訪問過了
    vis[u] = true;

    if(imax < weight[u]){
        head = u;//找出最大的一個點 即head
        imax = weight[u];
    }
    aofw += (weight[u] / 2);//記錄這個團伙的總通話時間
    atuan++;//記錄這個團伙的人數

    //深度優先
    for(int i = 0;i < SumMember;i++)
        //當與u相接的點(imp = 0)沒有被訪問(vis[i] = false)
        if(vis[i] == false && imap[u][i] != 0){
            DFS(i);
    }
}

void DFSTraver(int K){
    for(int i = 0;i < SumMember;i++){
        //當i沒有被訪問時
        if(vis[i] == false){
            //置零
            head = 0,imax = 0,aofw = 0,atuan = 0;
            DFS(i);
            if(atuan >= 3 && aofw > K){
                vec1.push_back(head);
                vec2.push_back(atuan);
                sumP++;
            }
        }
    }
}
int change(string str){
    //當str已經存在時返回它對應的下標
    if(srtoi.find(str) != srtoi.end())
        return srtoi[str];
    //否則insert str 並且給它一個下標
    else{
        srtoi[str] = SumMember;
        itos[SumMember] = str;
        return SumMember++;
    }
}

int main(int argc, char const *argv[]) {
    //N-總人數 K-最大權
    int N,K;

    scanf("%d%d",&N,&K);

    for(int i = 0;i < N;i++){
        //通話人G1、G2 通話時間len
        string G1,G2;
        int len;

        cin >> G1 >> G2;
        scanf("%d",&len);

        //返回G1、G2所對的下標
        int x1 = change(G1);
        int x2 = change(G2);

        //對參與點的權值+len
        weight[x1] += len;
        weight[x2] += len;
        //鄰接矩陣的點加上權值
        imap[x1][x2] += len;
        imap[x2][x1] += len;
    }

    DFSTraver(K);

    printf("%d\n",sumP);

    for(int i = 0;i < sumP;++i)
        cout << itos[vec1[i]] << " " << vec2[i] << "\n";
    return 0;
}