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

原创 2012年03月26日 17:47:29

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;
}


 

杭电ACM 1002:A+B Problem II

刷题第三篇,这一题看似也比较简单,但是一做就错,花费了很大力气才把他搞定。切记一定要亲自用笔画图算出,这样收获才会更大。原题回顾Problem Description I have a very ...
  • Always2015
  • Always2015
  • 2015年04月07日 22:27
  • 3416

HDU5688 Problem D【字符串排序+MAP】

Problem D Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To...
  • tigerisland45
  • tigerisland45
  • 2017年07月25日 19:59
  • 388

北邮ACM新生赛2015 题解

比赛地址 没权限找不到=_=。。。题目为http://code.bupt.edu.cn/的616, 614, 605, 604, 440, 620, 621, 619, 617。 A. A...
  • skywalkert
  • skywalkert
  • 2015年03月15日 23:10
  • 1643

解决Godaddy付款时的There was a problem processing your transaction. Please verify your payment information

今天不上班,帝都人民喜迎
  • jiluben
  • jiluben
  • 2014年11月10日 16:35
  • 3309

6TH HUNAN COLIGIANTE PROGRAMING CONTEST -- PROBLEM D

Since I'm on the road to IELTS,all my articals in this period will be english!Here's simple problem ...
  • Rickylv
  • Rickylv
  • 2010年11月09日 21:39
  • 439

In this problem, your task is to calculate SUM(n) = 1 + 2 + 3 + ... + n.

#include main() {int m=0,i,n;  while (scanf("%d",&n)!=EOF)  {for (i=1;i  m=m+i;  printf("%d",m);   ...
  • shuaiqidexiaojiejie
  • shuaiqidexiaojiejie
  • 2015年07月20日 11:16
  • 1182

acm之递归题目7

Problem DescriptionHDU 2006’10 ACM contest的颁奖晚会隆重开始了! 为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:首...
  • shelly1072
  • shelly1072
  • 2016年06月26日 11:06
  • 534

杭电ACM 2055:An easy problem

原创作品 转载请注明出处http://blog.csdn.net/always2015/article/details/45539811简单题,主要考虑出如何表示各个字母在字母表中的位置。我的AC代码...
  • Always2015
  • Always2015
  • 2015年05月06日 19:34
  • 756

2016 acm香港网络赛 A题 A+B Problem (FFT)

题意:给你一堆数,然后求ai+aj=ak的组成的(i,j,k)对有多少个,并且保证i,j,k小标互不相同。 题解: num[k]表示(ai,aj)=k的个数。然后将a[i]+a[i]的那种重复的去掉。...
  • liangzhaoyang1
  • liangzhaoyang1
  • 2016年10月07日 20:47
  • 1730

HDOJ4300Clairewd’s message【扩展KMP】

Clairewd’s message Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe...
  • R1986799047
  • R1986799047
  • 2015年08月18日 21:21
  • 496
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:n.boj 389 Shaking Your Cellphone(6th bupt acm problem D)
举报原因:
原因补充:

(最多只允许输入30个字)