1016. Phone Bills (25)

本文介绍了一个基于不同时间段费率变化的电话计费系统的实现过程。系统能够根据用户的通话记录自动计算出每月的费用,并考虑了时间戳匹配及排序等细节问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A long-distance telephone company charges its customers by the following rules:

Making a long-distance call costs a certain amount per minute, depending on the time of day when the call is made. When a customer starts connecting a long-distance call, the time will be recorded, and so will be the time when the customer hangs up the phone. Every calendar month, a bill is sent to the customer for each minute called (at a rate determined by the time of day). Your job is to prepare the bills for each month, given a set of phone call records.

Input Specification:

Each input file contains one test case. Each case has two parts: the rate structure, and the phone call records.

The rate structure consists of a line with 24 non-negative integers denoting the toll (cents/minute) from 00:00 - 01:00, the toll from 01:00 - 02:00, and so on for each hour in the day.

The next line contains a positive number N (<= 1000), followed by N lines of records. Each phone call record consists of the name of the customer (string of up to 20 characters without space), the time and date (mm:dd:hh:mm), and the word "on-line" or "off-line".

For each test case, all dates will be within a single month. Each "on-line" record is paired with the chronologically next record for the same customer provided it is an "off-line" record. Any "on-line" records that are not paired with an "off-line" record are ignored, as are "off-line" records not paired with an "on-line" record. It is guaranteed that at least one call is well paired in the input. You may assume that no two records for the same customer have the same time. Times are recorded using a 24-hour clock.

Output Specification:

For each test case, you must print a phone bill for each customer.

Bills must be printed in alphabetical order of customers' names. For each customer, first print in a line the name of the customer and the month of the bill in the format shown by the sample. Then for each time period of a call, print in one line the beginning and ending time and date (dd:hh:mm), the lasting time (in minute) and the charge of the call. The calls must be listed in chronological order. Finally, print the total charge for the month in the format shown by the sample.

Sample Input:
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line
Sample Output:
CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

一题写了一天,我又被自己蠢哭了。不过呢,也算有收获,对结构体排序有些开窍了。就是用一个结构体列表作为下标,用链接表连接上内容,当作数组那样排序。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define NAMELENGTH 21
#define STATUSLENGTH 9
#define MAXRECORD 1001
#define INF 0x3f3f3f

/**< 记录不同时段的收费,其中toll[24]是记得一天总费用 */
int toll[25];

/**< 客户记录节点, 一个客户对应一个这样的节点,每个节点最多存放1000条记录 */
struct CutNode
{
    int records[MAXRECORD];
    int nums;
};
typedef struct CutNode Customer;
typedef struct CutNode *PtrToCNode;

/**< 记录客户的列表 */
typedef struct LNode
{
    char name[NAMELENGTH];
    PtrToCNode Guest;

}CsmrList[MAXRECORD];

/**< 通过名字找出列表中是否有这名客户,有就返回客户的在列表中的下标,没有就返回-INF */
int findCustomer(CsmrList CList, int numOfCsmer, char name[NAMELENGTH]);
int findCustomer(CsmrList CList, int numOfCsmer, char name[NAMELENGTH])
{
    int i;
    for(i=0; i<numOfCsmer; i++)
    {
        if(strcmp(CList[i].name, name) == 0)
            return i;
    }
    return -INF;
}

/**< 测试用函数,用来输出列表中全部内容 */
void printAll(CsmrList clist, int numOfCsmer);
void printAll(CsmrList clist, int numOfCsmer)
{
    int i, j;
    printf("Total: %d customers\n", numOfCsmer);
    for(i=0; i<numOfCsmer; i++)
    {
        int numOfRec = clist[i].Guest->nums;
        for(j=0; j<numOfRec; j++)
        {
            printf("[%d]%s has[%d]->%d : %d\n", i, clist[i].name, numOfRec, j, clist[i].Guest->records[j]);
        }
    }
}

/**< 按名字排列客户在列表中的顺序 */
void sortName(CsmrList CList, int numOfCsmer);
void sortName(CsmrList CList, int numOfCsmer)
{
    int i, j;
    for(i=0; i<numOfCsmer; i++)
    {
        for(j=0; j<numOfCsmer-1-i; j++)
        {
            if(strcmp(CList[j].name, CList[j+1].name)>0)
            {
                char tmpN[NAMELENGTH];
                strcpy(tmpN, CList[j].name);
                strcpy(CList[j].name, CList[j+1].name);
                strcpy(CList[j+1].name, tmpN);

                PtrToCNode tmpC = CList[j].Guest;
                CList[j].Guest = CList[j+1].Guest;
                CList[j+1].Guest = tmpC;
            }
        }
    }
}

/**< 对同一个客户的所有记录,按照时间序排列 */
void sortRec(CsmrList CList, int numOfCsmer);
void sortRec(CsmrList CList, int numOfCsmer)
{
    int i, j, z;

    for(z=0; z<numOfCsmer; z++)
    {
        int numOfRec = CList[z].Guest->nums;
        for(i=0; i<numOfRec; i++)
        {
            for(j=0; j<numOfRec-1-i; j++)
            {
                if((CList[z].Guest->records[j]/10)>(CList[z].Guest->records[j+1]/10))
                {
                    //printf("%d VS %d\n", (CList[z].Guest->records[j]/10), (CList[z].Guest->records[j+1]/10));
                    int tmpRec = CList[z].Guest->records[j];
                    CList[z].Guest->records[j] = CList[z].Guest->records[j+1];
                    CList[z].Guest->records[j+1] = tmpRec;
                }

            }
        }

    }
}

/**< 找出on和off对应的有效记录,把无效记录忽略 */
void findRec(CsmrList CList, int numOfCsmer);
void findRec(CsmrList CList, int numOfCsmer)
{
    int i, j;

    for(i=0; i<numOfCsmer; i++)
    {
        int tmpRec[MAXRECORD] = {0};
        PtrToCNode tmpGuest = CList[i].Guest;
        int numOfRec = tmpGuest->nums;
        int validRec = 0;

        for(j=0; j<numOfRec; j++)
        {
            int sts1, sts2;
            sts1 = tmpGuest->records[j]%10;
            if(sts1 == 1 && j<(numOfRec-1))
            {
                sts2 = tmpGuest->records[j+1]%10;
                if(sts1 == 1 && sts2 == 0)
                {
                    tmpRec[validRec++] = tmpGuest->records[j];
                    tmpRec[validRec++] = tmpGuest->records[j+1];
                    j++;
                }
            }
        }

        tmpGuest->nums = validRec;
        for(j=0; j<tmpGuest->nums ;j++)
        {
            tmpGuest->records[j] = tmpRec[j];
        }

    }
}

/**< 将一串int数字形式的记录转化为int数组 */
void intToTime(int *t1, int *t2, int a, int b);
void intToTime(int *t1, int *t2, int a, int b)
{
    int i;
    a /= 10;
    b /= 10;
    for(i=2; i>=0; i--)
    {
        t1[i] = a%100;
        t2[i] = b%100;
        a /=100;
        b /=100;
    }
}

/**< 采用计算费用的办法是,假设从月初算,电话一直打到记录的时间为止,这段费用是多少,然后再把两个记录算得的费用相减 */
/**< 计算出该条记录从月初到记录时收费多少 */
int oneRecPay(int *a);
int oneRecPay(int *a)
{
    int pay = 0;
    pay = (a[0]-1)*toll[24];
    int i;
    for(i=0; i<a[1]; i++)
    {
        pay += toll[i]*60;
    }
    pay += toll[a[1]]*a[2];

    return pay;
}

/**< 计算id为guestID的客户名下所有记录 */
void csmrPay(CsmrList CList, int guestID);
void csmrPay(CsmrList CList, int guestID)
{
    int i, j;
    PtrToCNode tmpGuest = CList[guestID].Guest;
    int numOfRec = tmpGuest->nums;
    float totalPAY = 0;
    float pay;
    for(i=0; i<numOfRec; i+=2)
    {
        pay = 0;
        int t1[3], t2[3];
        intToTime(t1, t2, tmpGuest->records[i], tmpGuest->records[i+1]);
        int pay1 = oneRecPay(t1);
        int pay2 = oneRecPay(t2);
        pay = pay2 - pay1;
        int min1 = (t1[0]-1)*1440 + t1[1]*60 + t1[2];
        int min2 = (t2[0]-1)*1440 + t2[1]*60 + t2[2];
        int totalMin = min2 - min1;
        pay /= 100;
        printf("%02d:%02d:%02d %02d:%02d:%02d %d $%0.2f\n", t1[0], t1[1], t1[2], t2[0], t2[1], t2[2], totalMin, pay);
        totalPAY += pay;
    }
    printf("Total amount: $%0.2f", totalPAY);
}

int main()
{
    int i;
    /**< 录入分段收费价格 */
    toll[24] = 0;

    for(i=0; i<24; i++)
    {
        scanf("%d", &toll[i]);
        toll[24] += (toll[i]*60);
    }

    //printf("toll[%d]:%d inputed\n", 24, toll[24]);

    /**< 录入电话记录 */
    int numOfRec;
    scanf("%d", &numOfRec);
    CsmrList CList;
    for(i=0; i<numOfRec; i++)
    {
        CList[i].Guest = NULL;
    }


    int numOfCsmer = 0;
    int mm, dd, hh, mins;
    char name[NAMELENGTH];
    char status[STATUSLENGTH];
    for(i=0; i<numOfRec; i++)
    {
        scanf("%s %d:%d:%d:%d %s", name, &mm, &dd, &hh, &mins, status);
        /**< 找一下是否已经存在这个客户 */
        int guestID = findCustomer(CList, numOfCsmer, name);
        int sts = 0;
        if(strcmp(status, "on-line")==0)
        {
            sts = 1;
        }
        /**< 存在就在他名下新增一条记录*/
        if(guestID!=-INF)
        {

            int tmpRecID = CList[guestID].Guest->nums++;
            CList[guestID].Guest->records[tmpRecID] = sts + mins*10 + hh*1000 + dd*100000 + mm*10000000;
            //printf("[%d]%s rec[%d]: %d\n\n", guestID, CList[guestID].name, CList[guestID].Guest->nums-1, CList[guestID].Guest->records[tmpRecID]);
        }
        else
        {/**< 不存在这个客户,就新建一个 */
            PtrToCNode newCsmer = (PtrToCNode)malloc(sizeof(struct CutNode));
            newCsmer->nums = 1;
            newCsmer->records[0] = sts + mins*10 + hh*1000 + dd*100000 + mm*10000000;

            strcpy(CList[numOfCsmer].name, name);
            CList[numOfCsmer].Guest = newCsmer;
            numOfCsmer++;
            //printf("[%d]%s rec[%d]: %d\n\n", numOfCsmer-1, CList[numOfCsmer-1].name, 0, CList[numOfCsmer-1].Guest->records[0]);
        }

    }
    /**< 调整CList里记录的顺序 */
    sortName(CList, numOfCsmer);
//    printf("\n");
//    printAll(CList, numOfCsmer);
//    printf("\n");
    sortRec(CList, numOfCsmer);
//    printAll(CList, numOfCsmer);
//    printf("\n");
    findRec(CList, numOfCsmer);
//    printAll(CList, numOfCsmer);
//    printf("\n");

    bool IsFirst = true;
    for(i=0; i<numOfCsmer; i++)
    {
        if(CList[i].Guest->nums>0)
        {
            if(!IsFirst)
                printf("\n");
            printf("%s %02d\n", CList[i].name, CList[i].Guest->records[0]/10000000);
            csmrPay(CList, i);
            IsFirst = false;
        }

    }
    system("pause");
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值