我也遇到了卡70分的情况。
后来发现是收到REQ报文且接收者不为H(即服务器时),寻找该发送者使用的IP记录时忘了筛选state=1条件,使用了get_ip_by_name,已在注释中醒目位置标出。
// csp 2021 4
// 这种命令解析类的大模拟题不要用class,直接用struct + 全局函数就行了。
// 命令的解析在main里一把梭,因为这样省掉了传参抄写的步骤,不容易错。而且解析不正确可以直接continue。
// if else if未必没有switch优雅没,又不是golang
// 不是写工程,用不着给枚举命名,浪费时间和脑细胞
// 在解析命令之前,使用该命令的时间先更新所有IP的状态(是否过期),相当于离散化。
// 能用while(m--)就别用for(i from 1 to m),因为经常手残用i去索引,但实际上i指的是循环轮数
#include <iostream>
#include <string>
using namespace std;
int N, Tdef, Tmax, Tmin;
int n;
string H;
const int maxn = 10010;
// 不需要初始化,放在全局区默认都是0
struct IP {
int state; // 0 未分配 1 待分配 2 占用 3 过期
int due;
string owner;
} ips[maxn];
void update_all_ips(int tc) {
// 注意地址池大小是大N
for (int i = 1; i <= N; ++i) {
if (ips[i].due && (ips[i].due <= tc)) {
if (ips[i].state == 1) {
ips[i].state = 0;
ips[i].owner = "";
ips[i].due = 0;
} else {
ips[i].state = 3;
ips[i].due = 0;
}
}
}
}
int get_ip_by_state(int state) {
for (int i = 1; i <= N; ++i) {
if (ips[i].state == state) {
return i;
}
}
return 0;
}
int get_ip_by_name(string name) {
for (int i = 1; i <= N; ++i) {
if (ips[i].owner == name) {
return i;
}
}
return 0;
}
int main(int argc, char const *argv[])
{
cin >> N >> Tdef >> Tmax >> Tmin >> H;
cin >> n;
while (n--) {
int ti;
string sender, recver, type;
int ip, due;
cin >> ti >> sender >> recver >> type >> ip >> due;
if ((recver != H) && (recver != "*")) {
if (type != "REQ") {
continue;
}
}
// 这里是并且的关系
if ((type != "DIS") && (type != "REQ")) {
continue;
}
if ((recver == "*") && (type != "DIS")) {
continue;
}
if ((recver == H) && (type == "DIS")) {
continue;
}
update_all_ips(ti);
if (type == "DIS") {
// 这个ip遮蔽了cin读到的ip
int ip = get_ip_by_name(sender);
// 这里忘记了用ip = 来接收值
// 这里忘了未分配的状态代号是0
if (!ip) ip = get_ip_by_state(0);
if (!ip) ip = get_ip_by_state(3);
if (!ip) continue;
ips[ip].state = 1;
ips[ip].owner = sender;
if (due == 0) {
ips[ip].due = ti + Tdef;
} else {
ips[ip].due = due;
// Tmin和Tmax是时间,不是时刻
ips[ip].due = max(ti + Tmin, ips[ip].due);
ips[ip].due = min(ti + Tmax, ips[ip].due);
}
cout << H << ' ' << sender << ' ' << "OFR" << ' ' << ip << ' ' << ips[ip].due << endl;
} else if (type == "REQ") {
if (recver != H) {
// **非常重要**:不能用get_ip_by_name,因为其是不考虑state=几的。
// 可能会有该发送者ip值小但state不为1的记录(比如过期还没有更新)
// 不对↓(70分)
// int ip = get_ip_by_name(sender);
// if (!ip) continue;
// if (ips[ip].state == 1) {
// ips[ip].state = 0;
// ips[ip].owner = "";
// ips[ip].due = 0;
// continue;
// }
// 对↓(100分)
for (int i = 1; i <= N; ++i) {
if ((ips[i].owner == sender) && (ips[i].state == 1)) {
ips[i].state = 0;
ips[i].owner = "";
ips[i].due = 0;
break; // 可以break也可以不break,因为至多有一个state=1。加不加都是100分
}
}
continue;
}
// 下标是ip而不是i
if (!((1 <= ip) && (ip <= N) && (ips[ip].owner == sender))) {
cout << H << ' ' << sender << ' ' << "NAK" << ' ' << ip << ' ' << 0 << endl;
continue;
}
ips[ip].state = 2;
ips[ip].owner = sender;
if (due == 0) {
ips[ip].due = ti + Tdef;
} else {
ips[ip].due = due;
}
// Tmin和Tmax是时间段
ips[ip].due = max(ti + Tmin, ips[ip].due);
ips[ip].due = min(ti + Tmax, ips[ip].due);
cout << H << ' ' << sender << ' ' << "ACK" << ' ' << ip << ' ' << ips[ip].due << endl;
}
}
return 0;
}
其实不可能会有一个主机名对应两个IP及以上的情况,作者原来的七十分的写法是对的
感谢!
多谢大佬指点,我卡在这一直不知道哪错了