PTA 6-6 工作备忘录的生成(链表)

题目:

每天都要处理很多事务,为了更好地安排工作,希望在每天开始工作前,根据工作记录,生成工作备忘录。首先输入工作记录数(大于0的一个整数),再逐条输入各条工作记录,每条工作记录包括:工作名,开始时间,结束时间。假设每项工作的开始时间均小于它的结束时间,并且各项工作的开始时间互不相同。

我们的工作是需要把这些工作记录按开始时间排序并输出,在输出时,如果某项工作与若干项工作冲突(在做该项工作时,需要同时做其它工作),则在该工作名前加'*'。

函数接口定义:

Node* add(Node *, Node *);
void display(Node *);

裁判测试程序样例:

#include<iostream>
#include <string>
using namespace std;
struct Node{
    string name;
    int start;
    int end;
    Node *next;
};
Node* add(Node *, Node *);
void display(Node *);
bool check(Node *head)
{
    if(head==NULL || head->next==NULL) return true;
    Node *p=head->next;
    if(head->start > p->start) return false;
    return check(p);
}
int main()
{
    Node *head=NULL, *p;
    int i, repeat;
    cin>>repeat;
    for(i=0;i<repeat;i++){
        p = new Node;
        cin>>p->name>>p->start>>p->end;
        p->next=NULL;
        head = add(head, p);
    }
    if(!check(head)) cout<<"ERROR"<<endl;
    display(head);
    return 0;
}

/* 请在这里填写答案 */

输入样例:

4
aaa 19 20
ccc 169 200
ddd 153 170
bbb 20 111

输出样例:

aaa 19 20
bbb 20 111
*ddd 153 170
*ccc 169 200

 代码+总结:

吐槽:

        我真的是非常讨厌函数题啊,你这一个个函数不写注释鬼知道你要干嘛啊!

分析:

        这道题很明显是链表的题.对于这种函数题,我们就先看主函数

int main()
{
    Node *head=NULL, *p;
    int i, repeat;
    cin>>repeat;
    for(i=0;i<repeat;i++){
        p = new Node;
        cin >> p->name >> p->start >> p->end;
        p->next=NULL;
        head = add(head, p);
    }
    if(!check(head)) cout<<"ERROR"<<endl;
    display(head);
    return 0;
}

         前面几行都不用讲的,所以直接从for循环的内容分析起。

        

        在for循环里,前三行代码相当于新建了一个节点并且输入数据。第四行出现了我们要写的第一个函数 add() ,看他的函数名和返回值,我们大致能想到 add() 的功能应该是吧当前节点连接到我们的链表之上,那么整个for循环就理解为创建了链表。

        for之后出现了一行的if,里面直接塞了一个check()函数。这又是啥玩意?好在check()他已经帮我们写好了:

bool check(Node *head)
{
    if(head==NULL || head->next==NULL) return true;
    Node *p=head->next;
    if(head->start > p->start) return false;
    return check(p);
}

      check()的大概功能就是检查链表,如果链表 某个节点的start属性的值 小于 下一个节点的start属性的值 就返回false。(简单来说就是看链表节点的排序是不是按照start的值从小到大排的)

       那么这一行就是说如果for创建的链表不满足规范的话就输出error,显然,正确的输出必定不会error,所以这一行其实是在提醒我们add()函数不是简单的把节点连接到链表上,而且生成的链表需要符合规范。(所以实际上没啥用啊这一行)

        最后一行就是display()函数了,很明显他要干的活就是输出链表的内容到屏幕上。

        总结一下我们要写的函数要干的活:

add():把p节点链接到以head为首节点的链表上,并且保证每次链接链表节点的start属性是从小到大的。

display():把链表按照个节点的顺序输出内容,并且判断每个节点前是否要加 *。

        add()比较好写,display()比较麻烦,主要麻烦的点是怎么判断时间是否冲突了。

Node* add(Node *head, Node *p)
{
    Node *temp = head;
    if (head == NULL) return p;  // 如果是空链表,直接返回p
    if (p->start < head->start)  // 如果比表头小,成为新表头
    {
        p->next = head;
        return p;
    }
    while (temp->next) // 中间
    {
        if (temp->start < p->start && temp->next->start > p->start)
        {
            p->next = temp->next;
            temp->next = p;
            return head;
        }
        temp = temp->next;
    }
    temp->next = p; // 末尾
    return head;
}

        对于每一个节点,我们都把他跟链表里面的其他节点进行比较操作来判断时间是否冲突。(这里用p表示待判断结点,q代表其他节点),那么时间重叠的只有下面四种情况:

         总结可以得出,p、q重叠 等价于 (p的start/end落在q内 或 q的start/end落在p内),在这里我多写了函数来判断是否有重叠的。

bool is_colide(Node*head, Node *p)  //判断重合
{
    Node *temp = head;
    while (temp)
    {
        if (p != temp)  // 排除自己
        {
            if (p->start > temp->start && p->start < temp->end) return true;
            if (p->end > temp->start && p->end < temp->end) return true;
            if (temp->start > p->start && temp->start < p->end) return true;
            if (temp->end > p->start && temp->end < p->end) return true;
        }
        temp = temp->next;
    }
    return false;
}

void display(Node *head)
{
    Node *temp = head;
    while (temp)
    {
        if (is_colide(head, temp))
            cout << "*" << temp->name << " " << temp->start << " " << temp->end << endl;
        else
            cout << temp->name << " " << temp->start << " " << temp->end << endl;
        temp = temp->next;
    }
}

完整代码:

Node* add(Node *head, Node *p)
{
    Node *temp = head;
    if (head == NULL) return p;  // 如果是空链表,直接返回p
    if (p->start < head->start)  // 如果比表头小,成为新表头
    {
        p->next = head;
        return p;
    }
    while (temp->next) // 中间
    {
        if (temp->start < p->start && temp->next->start > p->start)
        {
            p->next = temp->next;
            temp->next = p;
            return head;
        }
        temp = temp->next;
    }
    temp->next = p; // 末尾
    return head;
}

bool is_colide(Node*head, Node *p)  //判断重合
{
    Node *temp = head;
    while (temp)
    {
        if (p != temp)  // 排除自己
        {
            if (p->start > temp->start && p->start < temp->end) return true;
            if (p->end > temp->start && p->end < temp->end) return true;
            if (temp->start > p->start && temp->start < p->end) return true;
            if (temp->end > p->start && temp->end < p->end) return true;
        }
        temp = temp->next;
    }
    return false;
}

void display(Node *head)
{
    Node *temp = head;
    while (temp)
    {
        if (is_colide(head, temp))
            cout << "*" << temp->name << " " << temp->start << " " << temp->end << endl;
        else
            cout << temp->name << " " << temp->start << " " << temp->end << endl;
        temp = temp->next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值