跳转至

202104-3 DHCP服务器

100% 数据——模拟

模拟过程即可,具体过程参考代码注释。

代码实现
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
#define ll long long
using namespace std;
const int maxn = 10010;
int n, T;
ll Tdef, Tmax, Tmin;
map<string, int> NameToID;
int cnt;
string Name[maxn];
string sender, receiver, type;
int rTime, rIP, rOverdue;
bool Illegal() {
    // 遇到这些情况,不处理
    if (receiver != Name[1] && receiver != "*" && type != "REQ")
        // 接收主机为本机或 *,但类型不是 Request
        return true;
    if (type != "REQ" && type != "DIS")
        // 类型不是 Discover 或 Request
        return true;
    if (type == "DIS" && receiver == Name[1])
        // 接收主机是本机,且类型为 Discover
        return true;
    if (type != "DIS" && receiver == "*")
        // 接收主机为 *,且类型不是 Discover
        return true;
    return false;
}
enum IPState {
    // 描述某个 IP 的状态
    NOT_DISTRIBUTED,        // 未分配
    READY_FOR_DISTRIBUTION, // 待分配
    DISTRIBUTED,            // 占用
    OVERDUE                 // 过期
};
struct IP {
    IPState state;
    int owner;
    int overdue;
    IP() {
        state = NOT_DISTRIBUTED;
        owner = 0;
        overdue = 0;
    }
} ip[maxn];
int NumOfIP;
int IPHeld[maxn];
int distributeIP(int owner) {
    // 为发送主机分配地址
    // 发送主机有 IP,直接返回
    if (IPHeld[owner]) {
        return IPHeld[owner];
    }
    // 否则,寻找最小状态为未分配的 IP 地址
    for (int i = 1; i <= n; ++i) {
        if (ip[i].state == READY_FOR_DISTRIBUTION && ip[i].overdue <= rTime) {
            // 待分配 IP 到期变为未分配
            ip[i].state = NOT_DISTRIBUTED;
            ip[i].overdue = 0;
            IPHeld[ip[i].owner] = 0;
            ip[i].owner = 0;
        }
        if (ip[i].state == NOT_DISTRIBUTED) {
            return i;
        }
    }
    // 否则,寻找最小状态为过期的 IP 地址
    for (int i = 1; i <= n; ++i) {
        if (ip[i].state == DISTRIBUTED && ip[i].overdue <= rTime) {
            // 已分配 IP 过期变为过期 IP
            ip[i].state = OVERDUE;
            ip[i].overdue = 0;
        }
        if (ip[i].state == OVERDUE) {
            return i;
        }
    }
    // 否则,不处理该报文
    return 0;
}
void receiveDiscover() {
    // 接收到 Discover 报文
    int s = NameToID[sender];
    int curIP = distributeIP(s);
    if (!curIP) // 分配失败,不处理
        return;
    ip[curIP].state = READY_FOR_DISTRIBUTION; // IP 设为待分配
    IPHeld[ip[curIP].owner] = 0; // 原本占用的主机不在占用
    IPHeld[s] = curIP;           // 记录发送主机持有的 IP
    ip[curIP].owner = s;         // 标记该 IP 被发送主机持有
    // 设置过期时刻
    if (rOverdue == 0)
        ip[curIP].overdue = rTime + Tdef;
    else {
        if (rOverdue < rTime + Tmin) {
            ip[curIP].overdue = rTime + Tmin;
        } else if (rOverdue > rTime + Tmax) {
            ip[curIP].overdue = rTime + Tmax;
        } else {
            ip[curIP].overdue = rOverdue;
        }
    }
    // 向主机发送 Offer 报文
    cout << Name[1] << " " << Name[s] << " OFR " << curIP << " "
        << ip[curIP].overdue << "\n";
}
void receiveRequest() {
    // 接收到 Request 报文
    int s = NameToID[sender];
    // 不是本机
    if (receiver != Name[1]) {
        if (IPHeld[s] && ip[IPHeld[s]].state == READY_FOR_DISTRIBUTION) {
            ip[IPHeld[s]].state = NOT_DISTRIBUTED;
            ip[IPHeld[s]].overdue = 0;
            ip[IPHeld[s]].owner = 0;
            IPHeld[s] = 0;
        }
        return;
    }
    // 更新发送主机持有的 IP 的状态
    if (IPHeld[s] && ip[IPHeld[s]].overdue <= rTime) {
        if (ip[IPHeld[s]].state == READY_FOR_DISTRIBUTION) {
            ip[IPHeld[s]].state = NOT_DISTRIBUTED;
            ip[IPHeld[s]].owner = 0;
            ip[IPHeld[s]].overdue = 0;
            IPHeld[s] = 0;
        } else if (ip[IPHeld[s]].state == DISTRIBUTED) {
            ip[IPHeld[s]].state = OVERDUE;
            ip[IPHeld[s]].overdue = 0;
        }
    }
    // 检查 IP 是否在池内且占有者是发送主机
    if (!IPHeld[s] || IPHeld[s] != rIP) {
        cout << Name[1] << " " << Name[s] << " NAK " << rIP << " " << 0 << "\n";
        return;
    }
    // IP 地址状态设为占用
    ip[rIP].state = DISTRIBUTED;
    // 设置过期时刻
    if (rOverdue == 0)
        ip[rIP].overdue = rTime + Tdef;
    else {
        if (rOverdue < rTime + Tmin) {
            ip[rIP].overdue = rTime + Tmin;
        } else if (rOverdue > rTime + Tmax) {
            ip[rIP].overdue = rTime + Tmax;
        } else {
            ip[rIP].overdue = rOverdue;
        }
    }
    // 向主机发送 ACK 报文
    cout << Name[1] << " " << Name[s] << " ACK " << rIP << " "
        << ip[rIP].overdue << "\n";
}
int main() {
    // 读入数据,其中 Name[1] 是本机名称,本机编号为 1
    cin >> n >> Tdef >> Tmax >> Tmin >> Name[1];
    NameToID[Name[1]] = ++cnt;
    scanf("%d", &T);
    while (T--) {
        cin >> rTime >> sender >> receiver >> type >> rIP >> rOverdue;
        if (!NameToID.count(sender)) {
            NameToID[sender] = ++cnt;
            Name[cnt] = sender;
        }
        if (Illegal())
            continue;
        if (type == "REQ")
            receiveRequest();
        else if (type == "DIS")
            receiveDiscover();
    }
    return 0;
}

评论