您的位置:首页 > 其它

POJ1002 487-3279

2013-09-03 15:12 176 查看
POJ上的一道题目:企业想拥有令人难忘的电话号码。要一个电话号码让人容易记住,方法之一是号码里面有一个难忘的单词或词组拼写。例如,您可以拨打TUT- GLOP拨打沃特卢大学。有时电话号码只有一部分是单词拼写。当你回到你的酒店,今晚你可以通过拨打310 - GINO吉诺订购比萨饼。另一种方法,设计的电话号码是一个难忘的方式分组数字。你可以通过拨打必胜客"
3个10 "的号码3-10-10-10 来订购比萨.

  一个电话号码的标准形式是7个十进制数字用连字符之间的第三和第四位数字(如888-1200 ).一个电话的小键盘提供字母数字的映射,如下所示:

A,B和C映射到2

D,E和F映射到3

G, H和I映射到4

J,K,和L映射到5

M,N和O映射到6

P,R和S映射到7

T,U,和V映射到8

W,X,和Y映射到9的

  没有包括字母Q和Z的映射,连字符不能拨号,可以根据需要添加和删除. TUT- GLOP的标准形式是888-4567, 310 - GINO的标准形式是310-4466 , 3-10-10-10的标准形式是310-1010 。两个电话号码是等价的,如果它们具有相同的标准形式.(他们拨打同一个号码。 )你的公司正在编制当地企业的电话号码目录。作为质量控制过程的一部分,你要检查,没有两个(或以上)的企业目录中的有相同的电话号码.

  输入输入将包括一个案例。输入的第一行中指定的目录中的电话号码的数目(最多10万)作为单独行上的一个正整数.其余各行列出在目录中的电话号码,在单独一行的每个数字。每个电话号码的十进制数字,大写字母(不包括Q和Z )和连字符组成的字符串组成. 整整7个数字或字母的字符串中的字符.

产量

  生成一行输出为每个电话号码,任何形式多次出现。该行应得到的标准形式的电话号码,后跟一个空格,其次是在电话号码出现在目录的次数。电话号码升字典顺序排列输出线。如果没有重复在输入打印线:

No duplicates.

采样输入

12

4873279

ITS- EASY

888-4567

3-10-10-10

888 - GLOP

TUT- GLOP

967-11-11

310 - GINO

F101010

888-1200

-4-8-7-3-2-7-9 - 

487-3279

样本输出

310-1010 2

487-3279 4

888-4567 3

  这道题目解法多种多样,难点在于时间复杂度的控制,花了好长时间在这道题目上,下面说说我的经验;

  刚开始我想定义一个数据结构来存储,str字符数组用来存储每一个电话号码(去掉了'-'字符);identy用于存储字符数组的第一个字符,用于排序;icount用来统计每个相同号码的个数,用一个for循环实现起来并不复杂,可是程序一直是TLE(Time Limit Exceeded),查阅了一些资料,不服气自己的程序就是不能通过这道题,一直在修改修改再修改,后来发现,我从一开始就错了,我错的是我把电话号码当成一个字符数组来处理,还创建了结构体来存储,假设有10万个电话号码,还要排序,那时间复杂度就很高了,而且在循环体里面使用了strcmp,strcpy等库函数,花在这上面的时间,灰常多,继续在这上面修改,也不会有多好的效果的,在论坛上得到了大神的启发,转战用数字才存放电话号码,int类型的足矣.

typedef struct
{
int identy;
char str[9];
int icount;
}Phone;
于是,不采用结构体,直接用整型数组,这样不需要通过什么strcmp,strcpy函数来判断大小和赋值,也能直接用数组存储数据来排序,这样一来,时间复杂度将会大大减小。完整代码是:

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100000
int cmp(const void *a, const void *b)
{
int *x = (int *)a;
int *y = (int *)b;
return (*x) - (*y);
}
int main()
{
int cnt = 0;   //存放电话号码个数
int iter = 0;
int Noduplicates = 0;  //有无重复号码的标志,为0则表示无重复
int Sum = 0;
int icount = 0;
char ch;      // 接收键盘输入字符
int *PHONE = (int *)malloc(sizeof(int) * (MAXSIZE + 10));
scanf("%d",&cnt);
getchar();

//获取所有电话号码,转换为整型数据
for(iter = 0; iter < cnt; iter++)
{
Sum = 0;
ch = getchar();
while(ch != '\n')
{
if(ch >= '0' && ch <= '9')
{
Sum = Sum * 10 + ch - '0' ;
}
else if(ch >= 'A' && ch <= 'P')
{
Sum = Sum * 10 + (ch - 65) / 3 + 2 ;
}
else if(ch >= 'R' && ch <= 'Y')
{
Sum = Sum * 10 + (ch - 66) / 3 + 2 ;
}
ch = getchar();
}
PHONE[iter] = Sum;
}

//用快排对电话号码排序
qsort(PHONE, cnt, sizeof(int), cmp);

//输出排好顺序的号码
for(iter = 0, icount = 1; iter < cnt - 1 ; iter++)
{
icount = 1;
//统计重复号码个数
while(PHONE[iter] == PHONE[iter + 1])
{
iter++;
icount++;
}
if(icount > 1)
{
Noduplicates = 1;
printf("%03d-%04d %d\n",PHONE[iter] / 10000 ,PHONE[iter] % 10000 ,icount);
}
}
if(Noduplicates == 0)
{
printf("No duplicates.\n");
}
getchar();
return 0;
}
注: QZ 是不在映射里面的!还有就是输出格式,比如号码"000-0001"不应该输出"   -    1"(前导 0 的问题)

给几组测试用例:
 用例1:

2

---3333--3-3-3--

-3333333

输出:

333-3333 2

用例2:

4

0000000

0010001

0000000

0010001

输出:

000-0000 2

001-0001 2

要是这样你还不能AC,再看看下面几点建议:

1、数据量大时候果然要注意输入的时间,用cin超时,改用gets就AC了;

2、是不是原来是 "No duplicates." 少写了一个句号,或者后面多了一个空格输出格式有严格要求的;

3、如果自己写的快排不行,那可以试试系统的快排qsort(),我的程序就是用系统的快排;

4、用G++超时,但用C++AC了,-_-!!;

5、如果你是用字符数组才存储每个字符串(电话号码),字符串包括'-'字符,建议将数组长度开到40甚至100以上;

6、为了AC可以适当通过空间换取时间;

7、看到第7点建议,说明,我也不知道为什么了,你可以把原来的程序放一边,重新考虑其他算法,比如堆排序,hash算法,等通过了,再回头看看原来   的算法有什么不妥的地方,还是不行,请看第8点建议;

8、

注:本博客与博客园上的博客为同一博客主:http://www.cnblogs.com/bestDavid/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息