并查集应用

题目描述:

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
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<algorithm>
  5 using namespace std;
  6 #define N 1001
  7 typedef struct node{
  8     char name[4];//名字
  9     int time;//通话时间
 10 }Node;
 11 typedef struct gang{
 12     int head;//首领编号
 13 //    int mem[N];//成员的编号
 14     int num;//成员数目
 15     int weight;//总共通话时间
 16 }Gang;
 17 Node people[N];//用于记录每个人的信息 right
 18 int Tree[N];//用于并查集 right
 19 int k;//阈值 right
 20 Gang group[N];//统计每个组的情况 right
 21 int findRoot(int x){
 22     if(Tree[x]==-1) return x;
 23     else{
 24         int tmp=findRoot(Tree[x]);
 25         Tree[x]=tmp;
 26         return tmp;
 27     }
 28 }
 29 Gang* qsort(int Tree[],Gang group[],int num,int &count){//挑出符合的
 30     int i;
 31     //int count=0;
 32     for(i=0;i<num;i++){
 33         if(Tree[i]==-1&&group[i].weight>k&&group[i].num>2) count++;
 34     }
 35     Gang *ans;
 36     ans=(Gang*) malloc(sizeof(Gang)*count);
 37     int j=0;
 38     for(i=0;i<num;i++){
 39         if(Tree[i]==-1&&group[i].weight>k&&group[i].num>2){
 40         ans[j].head=group[i].head;
 41         ans[j].num=group[i].num;
 42         ans[j].weight=group[i].weight;
 43         j++;
 44         }
 45     }
 46     return ans;
 47
 48 }
 49 bool cmp(Gang a,Gang b){
 50
 51     return (strcmp(people[a.head].name,people[b.head].name)<0);
 52 }
 53 int main(){
 54     int n;//n 是记录数,k是阈值
 55     while(scanf("%d%d",&n,&k)!=EOF){
 56         int num=0;//当前人数
 57         int i;
 58         for(i=0;i<N;i++) Tree[i]=-1;
 59         //for(i=1;i<N;i++) sum[i]=0;
 60         while(n--!=0){
 61             char name1[4],name2[4];
 62             int s1,s2;//记录name在数组中位置
 63             int weight;//两人通话时长
 64             scanf("%s%s%d",name1,name2,&weight);
 65             for(i=0;i<num;i++){
 66                 if(strcmp(name1,people[i].name)==0)    break;//若已经存在
 67             }
 68             if(i==num){
 69                 strcpy(people[i].name,name1);
 70                 people[i].time=0;
 71                 group[i].num=1;
 72                 group[i].weight=0;
 73                 group[i].head=i;
 74                 num++;
 75             }
 76             s1=i;
 77             people[i].time+=weight;
 78
 79             for(i=0;i<num;i++){
 80                 if(strcmp(name2,people[i].name)==0) break;
 81             }
 82             if(i==num){
 83                 strcpy(people[i].name,name2);
 84                 people[i].time=0;
 85                 group[i].num=1;
 86                 group[i].weight=0;
 87                 group[i].head=i;
 88                 num++;
 89             }
 90             s2=i;
 91             people[i].time+=weight;
 92
 93             int s1_=findRoot(s1);
 94             int s2_=findRoot(s2);
 95             if(people[s1].time>people[group[s1_].head].time){//更新组里面的head
 96                 group[s1_].head=s1;
 97             }
 98             if(people[s2].time>people[group[s2_].head].time){//更新组里面的head
 99                 group[s2_].head=s2;
100             }
101             if(s1_!=s2_) {//合并
102                 Tree[s1_]=s2_;
103                 group[s2_].num+=group[s1_].num;
104                 group[s2_].weight+=(weight+group[s1_].weight);
105                 if(people[group[s2_].head].time<people[group[s1_].head].time){
106                     group[s2_].head=group[s1_].head;//
107                 }
108
109             }
110             else group[s2_].weight+=weight;
111
112
113
114
115
116         }
117         Gang* ans;
118         int count=0;
119         ans=qsort(Tree,group,num,count);
120         sort(ans,ans+count,cmp);
121         printf("%d\n",count);
122         for(i=0;i<count;i++){
123             printf("%s %d\n",people[ans[i].head].name,ans[i].num);
124         }
125
126     }
127
128 return 0;
129 }

时间: 2024-10-10 01:29:58

并查集应用的相关文章

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重

HDU 5606 tree 并查集

tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans?i??=size[findset(i)],size表示每个并查集根的size Ans_i=size[findset(i)],sizeAns?i??=size[findset(i)],size表示每个并查集根的sizesize. #include<cstdio> #include<cstring> #include<algorithm>

HDU 5441 离线处理 + 并查集

题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用并查集.离线处理,把边按权值排序,把问题按大小排序.然后离线的过程就是不断向图中加边的过程. 比如样例如下: 然后离线处理,排完序后将会是一条一条的加边:问题也排了序,因此是个累加过程... 1 #include <cstdio> 2 #include <iostream> 3 #in

poj1988 Cube Stacking(并查集

题目地址:http://poj.org/problem?id=1988 题意:共n个数,p个操作.输入p.有两个操作M和C.M x y表示把x所在的栈放到y所在的栈上(比如M 2 6:[2 4]放到[1 6]上为[2 4 1 6]),C x为输出x下面有几个数. 思路:并查集每个集合以栈最下面的数为根,维护两个数组num[x]表示x所在集合节点总数,count[x]表示x下方节点个数.每次查找压缩路径的时候更新count(换父节点的时候每轮都把父节点的count加给儿子,就可以一直更新到x所在栈

习题:过路费(kruskal+并查集+LCA)

过路费  [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费为所经过城市之间道路长度的最大值.如:A 到 B 长度为 2,B 到 C 长度为 3,那么开车从 A 经过 B 到 C 需要上交的过路费为 3. 佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此 他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低 的行驶路线.然

HDU3081Marriage Match II(二分答案+并查集+最大流SAP)经典

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2507    Accepted Submission(s): 856 Problem Description Presumably, you all have known the question of stable marriage match. A