【CSP】2021-04-3 DHCP服务器 大模拟 不使用任何算法

索引

历年CSP认证考试真题题解总汇持续更新

2021-04-3 DHCP服务器 大模拟 不使用任何算法

这题做完了就会发现并不难,但是做的时候感觉非常困难。做的时候出了很多bug并且找了很久很久也没有找到,发现自己找bug的效率很低,出bug 的效率却很高,有一些bug只看看不出来,必须要重新写的时候才能发现,这题一开始出了很多bug,虽然过了一些数据,但是有问题一直找不到然后心态有点崩,这时候回想起来,好像大脑就关闭了,不再思考,然后就找不到bug就很急,越急越不思考,然后就会浪费很多时间。

其次就是代码逻辑是否清晰,如果的清晰逻辑的代码那么出bug会很容易看出来,并且修bug也非常容易,如果逻辑不清楚,修bug会不断增加补丁,然后的逻辑越来越乱,越来越恶心,找到bug也越来越难,拿高分也就变成了不可能,所以一开始写的代码就要力求逻辑清晰,即使会有高的时间复杂度

还有一个事情,就是做第三题做多了,就想必须要用到map索引优化时间复杂度,有时候其实是没必要的,就比如这题,没必要用map,用来反而更复杂,不用也不会超出时间复杂度。

思路

一共分为三部分

第一部分是接受包然后检查是否要处理

第二部分是接受DIS包并发送OFR包

第三部分是接受REQ包并发送的ACK和NAK包

遇到的问题(一些逻辑不清晰导致的问题)

  1. 首先一开始没有想清楚要用的数据结构
//定义了IP的结构体
struct ip
{
    int state = 0; // 状态 0未分配 1待分配 2占用 3过期
    int addr;      // 地址
    string user; // 占用者
    long long timeout = 0;
};

实际上根本没有用到addr这个变量,也没有初始化,是直接用的下标表示的ip地址,但是有一个地方就脑抽直接用了这里的addr然后就导致出问题了,因为addr从来没有初始化

    if (d.user_to_ip.count(m.sender) && d.pool[d.user_to_ip[m.sender]].user == m.sender)
    {
        ip_addr=d.pool[d.user_to_ip[m.sender]].addr;
    }

然后这个错误找了很久很久找到,可见逻辑清晰多么重要

在这里插入图片描述

改了之后

在这里插入图片描述

  1. 其次就是为了节省那一点点时间复杂度,就把遍历更新状态和遍历查找放在了一起,这样的逻辑很复杂,不清晰,应该分开做的。

不分开做导致req处理req的时候没有更新状态,只有接收到DIS报文的时候才更新,这样是有问题的,所以以后不要用那一点点小聪明想要减少时间复杂度,是不可行的,并且还可能导致bug找不到,正确的是先清晰的写,后续再优化。

在这里插入图片描述

  1. 还有判断超时时刻的出现问题,搞混了变量名的意义

在写req的时候,判断超时时刻的逻辑直接复制req 的就没多想,然后没成想就少复制一段

        long long timeout = max(d.Tmin + m.t, m.time_out);
        timeout = min(d.Tmax + m.t, timeout);
        d.pool[m.ip].timeout = timeout;

就只复制了这一段,没有判断报文的超时时刻是不是0,如果是0则应该timeout=Tdef+m.t

然后变成了这样

    if (m.t == 0)
    {
        d.pool[m.ip].timeout = m.t + d.Tdef;
    }
    else
    {
        long long timeout = max(d.Tmin + m.t, m.time_out);
        timeout = min(d.Tmax + m.t, timeout);
        d.pool[m.ip].timeout = timeout;
    }

然后还是有错误,是变量用错了

    if (m.time_out == 0)
    {
        d.pool[m.ip].timeout = m.t + d.Tdef;
    }
    else
    {
        long long timeout = max(d.Tmin + m.t, m.time_out);
        timeout = min(d.Tmax + m.t, timeout);
        d.pool[m.ip].timeout = timeout;
    }

应该是这样

这个bug 找了好久好久

然后就拿到了70分

在这里插入图片描述

  1. 最后还是因为使用stl的自己想的逻辑比较复杂,然后就导致出现问题,没有找出来bug只能拿到70分,然后又重新写了一版不用stl的,直接就100分了,非常的顺利

在这里插入图片描述

用stl70分完整代码

#include <bits/stdc++.h>
using namespace std;
struct ip
{
    int state = 0; // 状态 0未分配 1待分配 2占用 3过期
    // int addr;      // 地址
    string user; // 占用者
    long long timeout = 0;
};
struct DHCP
{
    long long N, Tdef, Tmax, Tmin;
    struct ip pool[10010];
    unordered_map<string, int> user_to_ip;
    string H;
} d;
map<string, int> string_to_type;
struct message
{
    long long t;
    string sender;
    string receiver;
    int type; // 0 DIS 1 OFR 2 REQ 3 ACK 4 NAK
    int ip;
    long long time_out; // 过期时刻
};
bool checkRecieve(struct message m)
{
    if (m.receiver != d.H && m.receiver != "*")
    {
        if (m.type != 3)
        {
            return false;
        }
    }
    if (m.type != 1 && m.type != 3)
    {
        return false;
    }
    if ((m.receiver == "*" && m.type != 1) || (m.receiver == d.H && m.type == 1))
    {
        return false;
    }
    return true;
}
void update(int t)
{
    for (int i = 1; i <= d.N; i++)
    {
        if (d.pool[i].state == 1 && d.pool[i].timeout <= t && d.pool[i].timeout)
        {
            d.pool[i].state = 0;
            d.user_to_ip.erase(d.pool[i].user);
            d.pool[i].timeout = 0;
            d.pool[i].user.clear();
        }
        if (d.pool[i].state == 2 && d.pool[i].timeout <= t && d.pool[i].timeout)
        {
            d.pool[i].state = 3;
            d.pool[i].timeout = 0;
        }
    }
}
// int get_ip_by_user(string name)
// {
//     for (int i = 1; i < d.N; i++)
//         if (d.pool[i].user == name)
//             return i;
//     return 0;
// }
void deal_dis(struct message m)
{
    int ip_addr = -1;
    if (d.user_to_ip.count(m.sender) && d.pool[d.user_to_ip[m.sender]].user == m.sender)
    // if (int temp = get_ip_by_user(m.sender))
    {
        // ip_addr = temp;
        ip_addr=d.user_to_ip[m.sender];
    }
    else
    {
        for (int i = 1; i <= d.N; i++)
        {
            if (d.pool[i].state == 0)
            {
                ip_addr = i;
                break;
            }
        }
        if (ip_addr == -1) // 如果没有找到未分配的ip地址
        {
            for (int i = 1; i <= d.N; i++)
            {
                if (d.pool[i].state == 3)
                {
                    ip_addr = i;
                    break;
                }
            }
        }
        if (ip_addr == -1) // 如果连过期的也没有
        {
            return;
        }
    }
    d.pool[ip_addr].state = 1;
    d.user_to_ip.erase(d.pool[ip_addr].user); // 清楚上一个用户的痕迹
    d.pool[ip_addr].user = m.sender;
    d.user_to_ip[m.sender] = ip_addr;
    if (m.time_out == 0) // 如果过期时刻为0
    {
        d.pool[ip_addr].timeout = m.t + d.Tdef;
    }
    else
    {
        long long timeout = max(d.Tmin + m.t, m.time_out);
        timeout = min(d.Tmax + m.t, timeout);
        d.pool[ip_addr].timeout = timeout;
    }
    cout << d.H << ' ' << m.sender << ' ' << "OFR" << ' ' << ip_addr << ' ' << d.pool[ip_addr].timeout << endl;
}
void deal_req(struct message m)
{
    if (m.receiver != d.H)
    {
        int addr = d.user_to_ip[m.sender];
        // int addr = get_ip_by_user(m.sender);
        if (addr != 0 && d.pool[addr].state == 1)
        {
            d.user_to_ip.erase(m.sender);
            d.pool[addr].user.clear();
            d.pool[addr].timeout = 0;
            d.pool[addr].state = 0;
            return;
        }
        // for (int i = 1; i <= d.N; i++)
        // {
        //     if (d.pool[i].user == m.sender && d.pool[i].state == 1)
        //     {
        //         d.pool[i].state = 0;
        //         d.pool[i].user.clear();
        //         d.pool[i].timeout = 0;
        //     }
        // }
        // return;
    }
    if (m.ip <= 0 || m.ip > d.N || d.pool[m.ip].user != m.sender)
    {
        cout << d.H << ' ' << m.sender << ' ' << "NAK" << ' ' << m.ip << ' ' << 0 << endl;
        return;
    }

    d.pool[m.ip].state = 2;
    if (m.time_out == 0)
    {
        d.pool[m.ip].timeout = m.t + d.Tdef;
    }
    else
    {
        long long timeout = max(d.Tmin + m.t, m.time_out);
        timeout = min(d.Tmax + m.t, timeout);
        d.pool[m.ip].timeout = timeout;
    }

    d.user_to_ip.erase(d.pool[m.ip].user);
    d.user_to_ip[m.sender] = m.ip;
    d.pool[m.ip].user = m.sender;

    cout << d.H << ' ' << m.sender << ' ' << "ACK" << ' ' << m.ip << ' ' << d.pool[m.ip].timeout << endl;
}
int main()
{
    // freopen("1.txt", "r", stdin);
    cin >> d.N >> d.Tdef >> d.Tmax >> d.Tmin >> d.H;
    int n;
    cin >> n;
    string_to_type["DIS"] = 1, string_to_type["OFR"] = 2, string_to_type["REQ"] = 3;
    string_to_type["ACK"] = 4, string_to_type["NAK"] = 5;
    for (int i = 0; i < n; i++)
    {
        struct message temp;
        string type;
        cin >> temp.t >> temp.sender >> temp.receiver >> type >> temp.ip >> temp.time_out;
        temp.type = string_to_type[type];
        update(temp.t);
        if (!checkRecieve(temp))
        {
            continue;
        }
        if (temp.type == 1)
        {
            deal_dis(temp);
        }
        if (temp.type == 3)
        {
            deal_req(temp);
        }
    }
    return 0;
}

不用stl 100分完整代码

#include <bits/stdc++.h>
using namespace std;
struct ip
{
    int time_out = 0;
    int state = 0;
    string u = "";
};
struct dchp
{
    int N, Tdef, Tmax, Tmin;
    string H;
    struct ip pool[10010];
} d;
struct message
{
    string sender, reciver, type;
    int ip;
    int t;
    int time_out;
};
void update(int t)
{
    for (int i = 1; i < d.N; i++)
    {
        if (d.pool[i].time_out && d.pool[i].time_out <= t)
        {
            if (d.pool[i].state == 1)
            {
                d.pool[i].state = 0;
                d.pool[i].u.clear();
                d.pool[i].time_out = 0;
            }
            if (d.pool[i].state == 2)
            {
                d.pool[i].state = 3;
                d.pool[i].time_out = 0;
            }
        }
    }
}
bool check_reciver(struct message m)
{
    if (!(m.reciver == d.H || m.reciver == "*"))
    {
        if (m.type != "REQ")
        {
            return false;
        }
    }
    if (!(m.type == "DIS" || m.type == "REQ"))
    {
        return false;
    }
    if ((m.reciver == "*" && m.type != "DIS") || (m.reciver == d.H && m.type == "DIS"))
        return false;
    return true;
}
int get_ip_by_user(string name)
{
    for (int i = 1; i <= d.N; i++)
        if (d.pool[i].u == name)
            return i;
    return 0;
}
int get_ip_by_state(int state)
{
    for (int i = 1; i <= d.N; i++)
        if (d.pool[i].state == state)
            return i;
    return 0;
}
void deal_discover(struct message m)
{
    int addr = get_ip_by_user(m.sender);
    if (!addr)
        addr = get_ip_by_state(0);
    if (!addr)
        addr = get_ip_by_state(3);
    if (!addr)
        return;
    d.pool[addr].state = 1;
    d.pool[addr].u = m.sender;
    if (!m.time_out)
        d.pool[addr].time_out = m.t + d.Tdef;
    else
    {
        int time_out = min(m.time_out - m.t, d.Tmax);
        time_out = max(time_out, d.Tmin);
        d.pool[addr].time_out = m.t + time_out;
    }
    cout << d.H << ' ' << m.sender << ' ' << "OFR" << ' ' << addr << ' ' << d.pool[addr].time_out << endl;
}
void deal_request(struct message m)
{
    if (m.reciver != d.H)
    {
        for (int i = 1; i <= d.N; i++)
            if (d.pool[i].state == 1 && d.pool[i].u == m.sender)
            {
                d.pool[i].state = 0;
                d.pool[i].u.clear();
                d.pool[i].time_out = 0;
            }
        return;
    }
    if (!(m.ip > 0 && m.ip <= d.N && d.pool[m.ip].u == m.sender))
    {
        cout << d.H << ' ' << m.sender << ' ' << "NAK" << ' ' << m.ip << ' ' << 0 << endl;
        return;
    }
    d.pool[m.ip].state = 2;
    d.pool[m.ip].u = m.sender;
    if (!m.time_out)
        d.pool[m.ip].time_out = m.t + d.Tdef;
    else
    {
        int time_out = min(m.time_out - m.t, d.Tmax);
        time_out = max(time_out, d.Tmin);
        d.pool[m.ip].time_out = m.t + time_out;
    }
    cout << d.H << ' ' << m.sender << ' ' << "ACK" << ' ' << m.ip << ' ' << d.pool[m.ip].time_out << endl;
}
int main()
{
    // freopen("1.txt", "r", stdin);
    cin >> d.N >> d.Tdef >> d.Tmax >> d.Tmin >> d.H;
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        struct message m;
        cin >> m.t >> m.sender >> m.reciver >> m.type >> m.ip >> m.time_out;
        update(m.t);
        if (!check_reciver(m))
            continue;
        if (m.type == "DIS")
            deal_discover(m);
        else if (m.type == "REQ")
            deal_request(m);
    }
    return 0;
}

第二遍写 精简版100分

#include <bits/stdc++.h>
using namespace std;
struct message
{
    long long t;// 接收到的时间
    string sender,reciver,type;
    int ip;
    long long out_time;// 过期时间
};
struct ip
{
    int state = 1; // 1未分配 2待分配 3占用 4过期
    int out_time = 0;
    string user;
};
long long N,tdef,tmax,tmin;
struct ip pool[10001];
string H;
bool check_recive(const struct message m)
{
    if(m.reciver != H && m.reciver != "*")
    {
        if(m.type != "REQ")
            return false;
    }
    if(m.type != "DIS" && m.type != "REQ")
        return false;
    if((m.reciver == "*" && m.type != "DIS") || (m.reciver == H && m.type == "DIS"))
        return false;
    return true;
}
void update_state(int t)
{
    for(int i = 1; i <= N; i++)
    {
        if(pool[i].state == 2 &&t >= pool[i].out_time)
        {
            pool[i].state = 1;
            pool[i].user.clear();
            pool[i].out_time = 0;
        }
        if(pool[i].state == 3 && t >= pool[i].out_time)
        {
            pool[i].state = 4;
            pool[i].out_time = 0;
        }
    }
}
int get_ip_by_user(string user)
{
    for(int i = 1; i <= N; i++)
    {
        if(pool[i].user == user)
            return i;
    }
    return -1;
}
long long get_time_out(const struct message &m)
{
    if(!m.out_time) return m.t + tdef;
    if(m.out_time - m.t > tmax) return m.t + tmax;
    if(m.out_time - m.t < tmin) return m.t + tmin;
    return m.out_time;
}
void deal_discover(struct message m)
{
    int res = get_ip_by_user(m.sender);
    if(res == -1)
    {
        for(int i = 1; i <= N; i++)
        {
            if(pool[i].state == 1)
                {res = i; break;}
        }
    }
    if(res == -1)
    {
        for(int i = 1; i <= N; i++)
        {
            if(pool[i].state == 4)
                {res = i; break;}
        }
    }
    if(res == -1) return;
    pool[res].state = 2;
    pool[res].user = m.sender;
    pool[res].out_time = get_time_out(m);
    cout << H << ' ' << m.sender << ' ' << "OFR" << ' ' << res << ' ' << pool[res].out_time << endl;
}
void deal_req(const struct message &m)
{
    if(m.reciver != H)
    {
        for(int i = 1; i <= N; i++)
        {
            if(pool[i].state == 2 && pool[i].user == m.sender)
            {
                pool[i].state = 1;
                pool[i].user.clear();
                pool[i].out_time = 0;
            }
        }
        return;
    }
    if(!(m.ip >= 1 && m.ip <= N && pool[m.ip].user == m.sender))
    {
        cout << H << ' ' << m.sender << ' ' << "NAK" << ' ' << m.ip << ' ' << 0 << endl;
        return;
    }
    pool[m.ip].state = 3;
    pool[m.ip].out_time = get_time_out(m);
    cout << H << ' ' << m.sender << ' ' << "ACK" << ' ' << m.ip << ' ' << pool[m.ip].out_time << endl;
}
int main()
{
//    freopen("1.txt", "r", stdin);
    cin >> N >> tdef >> tmax >> tmin >> H;
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        struct message m;
        cin >> m.t >> m.sender >> m.reciver >> m.type >> m.ip >> m.out_time;
        if(!check_recive(m)) continue;
        update_state(m.t);
        if(m.type == "DIS") deal_discover(m);
        if(m.type == "REQ") deal_req(m);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值