n.boj 389 Shaking Your Cellphone(6th bupt acm problem D)

Problem D. Shaking Your Cellphone

Description
Do you know a software called "WeiXin", a kind of chatting tool? There is an 
application called "Shaking for a while". Once you shake your cellphone, you 
can find those who shake their cellphone at same time. 
One day when Tom was shaking his cellphone, he thought about a problem: 
how large the friends group would be if everyone made friends once they 
find others who shake cellphone at same time and combine their friends 
group? 
We assume all the people are lonely and have no friends at the beginning. In 
other word, their friends group only contains themselves.
Input
First line contains an integer T (0 < T <= 10), indicate there are T cases. 
For each case, the first line contains an integer N (0 < N <= 1000), indicate 
the number of people who would shake their cellphone. 
Then follows N lines. Every line comes with an integer K[i] (0 <= K[i] <= 
1440), indicate the i-th person shakes cellphone K times a day. Then follows 
K[i] strings shown as "HH:MM", indicate the time the i-th person shakes 
cellphone.
Output
For each test case, the first line contains an integer X indicate how many 
friends group amount the people; the second line comes X integers in non-descending order, indicate the scale of each friends group.
Sample Input
3 00:00 00:01 00:02 
2 00:01 00:03 
1 00:03 
1 00:04
 
Sample Output
1 3
Source
thomas0726
 
 
 
 
今年校赛现场赛D题,简单说一下题意:
N个人摇手机,给出每个人摇手机的次数和相应的时刻点;在同一时刻摇手机的人们在一个好友圈内,而且对于息好友的好友,也是自己的好友,表示如果在好友圈A的人和好友圈B的另一人是好友的话,表示好友圈A和好友圈B实际是同一个好友圈,好友圈A和好友圈B里面的人都相互是好友。求最后独立的好友圈有多少人,每个圈子的规范(人数)有多少,按升序输出。
 
解题思路:抽象而言,将每个人看成一个点,如果互为好友,则两点相连;间接相连的两点也是直接相连的;相连的点属于一个集合,求集合数及其相应规模。
数据结构很重要;如果数据结构用邻接矩阵记录两点连通性的话,直观的想法就得用floyd求连通性,然后求相应的集合。但floyd的时间复杂度为O(n^3),即10^9了,会超时。应该用并查集结构,一个以时刻点做下标的并查集,一个以用户ID做下标的并查集。时间并查集记录第一个在这个时刻点摇号的用户ID,同时在用户并查集中设置它的父结点为它自身。如果用户摇手机的时刻先前已经记录有用户摇过,则当前用户的用户并查集的父结点为此时刻的时间并查集结点对应的用户ID在用户并查集中的根父结点。
为了提高合并速度,在找父结点的过程中,要做些优化
int get_fa(int i){
    if (fa[i] == i)
        return i;
    return fa[i] = get_fa(fa[i]); //将中间结点的父结点都设成根结点,提高后续合并速率
}
最后再做些排序工作即可。

 
#include<stdio.h>
#include<stdlib.h>
 
 
int fa[1010]; // 并查集,值为父亲结点 
int tt[1500]; // time table
int grp[1010];
int get_fa(int i){
    if (fa[i] == i)
        return i;
    return fa[i] = get_fa(fa[i]);
}
 
int get_date(char* t){
    int m = (t[0] - '0') * 10 + (t[1] - '0');
    int s = (t[3] - '0') * 10 + (t[4] - '0');
    return m * 60 + s;
}
 
int cmp(const void* a, const void* b){
    return *(int*)a - *(int*)b;
}
 
main(){
    int T;
    int N;
    char str[6];
 
    scanf("%d", &T);
    while (T--){
        int i, j;
        scanf("%d", &N);
        for (i = 0; i < N; i++){
            fa[i] = i;
            tt[i] = -1;
            grp[i] = 0;
        }
        for (i = N; i < 1500; i++){
            tt[i] = -1;
        }    
        for (i = 0; i < N; i++){
            int K;
            scanf("%d", &K);            
            while (K--){
                scanf("%s", str);
                int t_index = get_date(str);
                if (tt[t_index] == -1)
                    tt[t_index] = get_fa(i);            
                fa[get_fa(i)] = get_fa(tt[t_index]);
            }            
        }
        for (i = 0; i < N; i++)
            fa[i] = get_fa(i);
 
        qsort(fa, N, sizeof(int), cmp);
        int count = 0;
        int gn = 0; //group No. ; from 0
        int cg = fa[0];
        count ++;
        for (i = 1; i < N; i++){
            if (cg == fa[i])
                count ++;
            else {
                cg = fa[i];
                grp[gn] = count;
                count = 1;
                gn ++;            
            }            
        }
        grp[gn++] = count;
        qsort(grp, gn, sizeof(int), cmp);
        printf("%d\n", gn);
        for (i = 0; i < gn; i++){
            if (i == 0)
                printf("%d", grp[i]);
            else
                printf(" %d", grp[i]);
        }
        putchar('\n');
    }            
    return 0;
}


 

觉得自己还是不太熟悉并查集,因为一些细节问题调了好阵子。。

看了官方公布的参考答案(如下),不由感叹大牛对数据结构的操纵力……

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<stack>
using namespace std;
typedef long long llong;
const double EPS=1e-9;
const double Pi=acos(-1.0);
int Fa[2500],Cnt[2500];
int GetFa(int x)
{
    if (Fa[x]==x)
       return x;
    return Fa[x]=GetFa(Fa[x]);
}
void Merge(int x,int y)
{
     Fa[GetFa(x)]=Fa[GetFa(y)];
}
int GetDate(char s[])
{
    int x=(s[0]-'0')*10+s[1]-'0';
    int y=(s[3]-'0')*10+s[4]-'0';
    return x*60+y;
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    int T,i,K,N;
    char st[10];
    scanf("%d",&T);
    while (T--)
    {
          for (i=0;i<2450;i++)
          {
              Fa[i]=i;
              Cnt[i]=0;
          }
          scanf("%d",&N);
          for (i=0;i<N;i++)
          {
              scanf("%d",&K);
              while (K--)
              {
                    scanf("%s",st);
                    Merge(i,GetDate(st)+1000);
              }
          }
          for (i=0;i<N;i++)
              Cnt[GetFa(i)]++;
          sort(Cnt,Cnt+2440);
          for (i=0;Cnt[i]==0;i++);
          printf("%d\n%d",2440-i,Cnt[i]);
          for (i++;i<2440;i++)
              printf(" %d",Cnt[i]);
          puts("");
    }
    system("pause");
    return 0;
}


 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值