~~学c以来已经两个月了,终于有能力刷甲级了,脱坑跨保之路漫长呐。
原题见
https://pintia.cn/problem-sets/994805342720868352/problems/994805493648703488
本答案适合跟笔者一样不会C++的小白食用。
1.数据的储存方式
题目要求按照字母序输出个人账单,账单每一项的输出以及on/off的匹配都依赖时间顺序。所以大体思路是建立一个包含通话记录结构的以个人为单位的结构体。思路之一是构建一个广义静态链表,然后分别对每个姓名结点及其通话记录进行排序,难点在于通话记录的容量不好确定。
笔者担心时间复杂度过高,放弃排序。直接使用不需考虑容量,便于插入操作的广义表结构。
结构设计如下
顾客结点定义如下
typedef struct CoNode *Costomer;
typedef struct CoNode{
char Name[21]; //注意多申请一个空间用来存放0
int Month;
Bill *Bills; //通话记录结点的入口
Costomer Next;
} * Head;
通话记录结点定义
typedef enum{Off,On}Type;
typedef struct TimeNode{
int Date,Hour, Minute;
} Time;
typedef struct BillNode{
Time time; //存放该条记录的月日时分
Type type; //记录on/off
struct BillNode *Next;
} Bill;
插入结点时结点指针从头扫描,直到结点为空或者比较函数不小0时停止。
其中顾客结点比较时直接调用strcmp(),时间结点比较的实现如下:
int BillCmp(Time t1,Time t2){
int m = t1.Date - t2.Date;
if(m)return m;
m = t1.Hour - t2.Hour;
if(m)return m;
m = t1.Minute - t2.Minute;
return m;
}
- on/off的判断
设计两个指向时间记录结点的指针B1,B2以及一个扫描指针temp,注意要初始化为NULL。当temp扫描到on状态的结点时,更新B1,指向off状态的结点时更新B2,此时做一次判定,假如B2不为空,则匹配成功,进行时间与金钱的计算。注意此时一个细节:匹配并且计算完成后需要把B1重置为NULL。
- 时间与金钱的计算
计算时间和金钱都可以通过一个函数,两个数组进行计算。计算话费时可以分别计算两个时间对00:00:00:00的相对花销,然后两组之差为所实际的话费。计算时间时可以将其看做权均为1的话费的计算实现如下:
float AbCost(Time t,int *toll){
float cost = t.Date * 60 * toll[24];
for (int i = 0; i < t.Hour;i++)
cost += 60 * toll[i];
cost += t.Minute * toll[t.Hour];
return cost;
}
float Cost(Time t1,Time t2,int *toll){
float cost1, cost2;
cost1 = AbCost(t1, toll);
cost2 = AbCost(t2, toll);
return cost2 - cost1;
}
C代码冗长,笔者也在努力学习C++了。所有代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum{Off,On}Type;
typedef struct TimeNode{
int Date,Hour, Minute;
} Time;
typedef struct BillNode{
Time time;
Type type;
struct BillNode *Next;
} Bill;
typedef struct CoNode *Costomer;
typedef struct CoNode{
char Name[21];
int Month;
Bill *Bills;
Costomer Next;
} * Head;
int BillCmp(Time t1,Time t2){
int m = t1.Date - t2.Date;
if(m)return m;
m = t1.Hour - t2.Hour;
if(m)return m;
m = t1.Minute - t2.Minute;
return m;
}
Head BuildInfo(int n){
Head H = (Head)malloc(sizeof(struct CoNode));
H->Next = NULL;H->Month=-1;
Costomer p, q;
char name[21], type[10];
int month;
while(n--){
Bill *B = (Bill *)malloc(sizeof(Bill));
scanf("%s %d:%d:%d:%d %s", name,&month,&B->time.Date,&B->time.Hour,&B->time.Minute,type);
B->type = (type[1] == 'n') ? On : Off;
for (p = H; p->Next && strcmp(p->Next->Name, name) < 0;p=p->Next);
if(p->Next&&strcmp(p->Next->Name,name)==0){
p = p->Next;
Bill *B2;
for (B2 = p->Bills; B2->Next && BillCmp(B2->Next->time, B->time) < 0;B2=B2->Next);
B->Next = B2->Next;
B2->Next = B;
}
else {
q = (Costomer)malloc(sizeof(struct CoNode));
strcpy(q->Name, name);
q->Month = month;
q->Next = p->Next;
p->Next = q;
q->Bills = (Bill *)malloc(sizeof(Bill));
q->Bills->Next = B;
q->Bills->Next->Next = NULL;
}
}
return H;
}
float AbCost(Time t,int *toll){
float cost = t.Date * 60 * toll[24];
for (int i = 0; i < t.Hour;i++)
cost += 60 * toll[i];
cost += t.Minute * toll[t.Hour];
return cost;
}
float Cost(Time t1,Time t2,int *toll){
float cost1, cost2;
cost1 = AbCost(t1, toll);
cost2 = AbCost(t2, toll);
return cost2 - cost1;
}
void PrintBills(Head H,int *toll){
Costomer p;
Bill *B1, *B2, *temp;
int min, i, time[24];float cost, sum, flag;
for(i=0;i<24;i++)
time[i] = 1;
time[24] = 24;
for (p = H->Next; p;p=p->Next){
B1 = B2 = NULL;sum=0;flag=1;
for (temp = p->Bills->Next; temp;temp=temp->Next){
if(temp->type==On)B1=temp;
else{
B2 = temp;
if(B1&&B2){
if(flag){
printf("%s %02d\n", p->Name, p->Month);
flag = 0;
}
cost = Cost(B1->time, B2->time, toll)/100;
sum += cost;
min =Cost(B1->time, B2->time, time);
printf("%02d:%02d:%02d ", B1->time.Date, B1->time.Hour, B1->time.Minute);
printf("%02d:%02d:%02d ", B2->time.Date, B2->time.Hour, B2->time.Minute);
printf("%d $%.2f\n", min, cost);
B1 = NULL;
}
}
}
if(!flag)printf("Total amount: $%.2f\n", sum);
}
}
int main(){
int i, n, toll[25];
for (i = toll[24] = 0; i < 24; i++){
scanf("%d", toll+i);
toll[24] += toll[i];
}
scanf("%d", &n);
Head H = BuildInfo(n);
PrintBills(H,toll);
return 0;
}