题目链接:http://pat.zju.edu.cn/contests/pat-practise/1016
以前在POJ上也见过类似的题,当时还不会qsort,菜的一米,遇到大数据还用链表做,还没等把输入处理完成,就已经头大的发麻了,看来我还是有一点进步的。
这道题我开了个record数组,记录所有的账单,第一步先根据字母表顺序将账单排序分类,在此要大大的感谢一把qsort,它可以数组内指定位置和指定长度进行排序,所以我就没有把账单记录分开存到各个客户名下,而是用qsort分割排序,和单独处理单个客户的账单效果一模一样。第二步,根据客户名称作为id,单独对当前处理的客户记录进行时间排序,然后处理,这道题逻辑有点小复杂,和昨天的那个银行排队一样,都属于无关算法而着重逻辑的,到最后的计算时间和费用有点棘手,不过把思路整清楚就OK了。
这道题要注意的陷阱就一点:1.如果客户A的账单记录没有任何一对是合法的,则客户A什么信息都不输出,估计电信局就这样设计的,一年应该可以省不少木材。^_^
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 typedef struct
6 {
7 char name[22];//名字
8 int month;//月份
9 int day;//天
10 int hour;//时
11 int minute;//分
12 char tag[10];//on-line or off-line
13 }record;
14
15 int n;
16 record *rd;
17 int rate[24];//费率
18 int count, start;//记录当前处理的这个用户的记录数目,和当前这个用户的第一条记录位置
19 double totalCharge;//该用户该月的费用合计
20
21 double charge(int sday, int shour, int sminute, int eday, int ehour, int eminute)//计算一条有效电话记录的时长和费用,并返回费用
22 {
23 double cost = 0;
24 long time = 0;
25
26 while(sday < eday)//先让天相等
27 {
28 time += (60 - sminute);
29 cost += (60 - sminute) * rate[shour];
30 sminute = 0; shour ++;//分化成0,时加1
31 time += 60 * (24 - shour);
32 while(shour < 24)
33 {
34 cost += 60 * rate[shour];
35 shour ++;
36 }
37 shour = 0; sday ++;//时化成0,天加1
38 }//天此时相等,时分为00:00
39 while(shour < ehour)//再让时相等
40 {
41 time += (60 - sminute);
42 cost += (60 - sminute) * rate[shour];
43 sminute = 0; shour ++;
44 }
45 time += (eminute - sminute);
46 cost += rate[ehour] * (eminute - sminute);
47
48 printf("%ld $%.2lf\n", time, cost / 100);
49
50 return cost / 100;
51 }
52
53 void totalCount()//数出当前要处理的客户的总记录数目
54 {
55 int i;
56 for(i = start + 1; i < n; i ++)
57 {
58 if(strcmp(rd[i].name, rd[i - 1].name) != 0)
59 {
60 break;
61 }
62 else
63 {
64 count ++;
65 }
66 }
67 }
68
69 int comp_name(const void *a, const void *b)
70 {
71 record c = *(record *)a;
72 record d = *(record *)b;
73
74
75 if(strcmp(c.name, d.name) <= 0) return -1;
76 else return 1;
77 }
78
79 int comp_time(const void *a, const void *b)
80 {
81 record c = *(record *)a;
82 record d = *(record *)b;
83
84 if(c.day < d.day) return -1;
85 else if(c.day > d.day) return 1;
86 else
87 {
88 if(c.hour < d.hour) return -1;
89 else if(c.hour > d.hour) return 1;
90 else
91 {
92 if(c.minute < d.minute) return -1;
93 else return 1;
94 }
95 }
96 }
97
98 int main()
99 {
100 int i;
101 int flag;//1应该出现offline, 0应该出现online
102 int onpos;//记录最近有效的on-line记录位置,为了算出charge
103 int sign;//0表示该客户名字和月份还没有输出,1表示已输出
104
105
106 while(scanf("%d", &rate[0]) != EOF)
107 {
108 for(i = 1; i < 24; i ++)
109 {
110 scanf("%d", &rate[i]);
111 }
112 scanf("%d", &n);
113 rd = (record *)malloc(n * sizeof(record));
114 for(i = 0; i < n; i ++)
115 {
116 scanf("\n%s %d:%d:%d:%d %s", rd[i].name, &rd[i].month, &rd[i].day, &rd[i].hour, &rd[i].minute, rd[i].tag);
117 }
118 qsort(rd, n, sizeof(record), comp_name);//先将记录按字母表顺序分类
119 count = 1; start = 0; totalCount(); sign = 0;
120 while(start < n)//整个记录表还没处理完
121 {
122 qsort(rd + start, count, sizeof(record), comp_time);
123 flag = 0;
124 totalCharge = 0;
125 for(i = start; i < start + count; i ++)//处理该客户
126 {
127 if(flag == 0)//期待出现online,如果是offline跳过
128 {
129 if(rd[i].tag[1] == 'f')//off-line
130 {
131 continue;
132 }
133 else//on-line
134 {
135 onpos = i;
136 flag = 1;
137 }
138 }
139 else//期待出现offline,如果是online则更新onpos
140 {
141 if(rd[i].tag[1] == 'n')//on-line
142 {
143 onpos = i;
144 }
145 else//off-line
146 {
147 if(sign == 0)
148 {
149 printf("%s %02d\n", rd[start].name, rd[start].month);
150 sign = 1;
151 }
152 printf("%02d:%02d:%02d %02d:%02d:%02d ", rd[onpos].day, rd[onpos].hour, rd[onpos].minute, rd[i].day, rd[i].hour, rd[i].minute);
153 totalCharge += charge(rd[onpos].day, rd[onpos].hour, rd[onpos].minute, rd[i].day, rd[i].hour, rd[i].minute);
154 flag = 0;
155 }
156 }
157 }
158 if(sign == 1)
159 {
160 printf("Total amount: $%.2lf\n", totalCharge);
161 }
162 start += count; count = 1; totalCount(); sign = 0;
163 }
164 }
165 return 0;
166 }