2021-04-3 DHCP服务器 大模拟 不使用任何算法
索引
2021-04-3 DHCP服务器 大模拟 不使用任何算法
这题做完了就会发现并不难,但是做的时候感觉非常困难。做的时候出了很多bug并且找了很久很久也没有找到,发现自己找bug的效率很低,出bug 的效率却很高,有一些bug只看看不出来,必须要重新写的时候才能发现,这题一开始出了很多bug,虽然过了一些数据,但是有问题一直找不到然后心态有点崩,这时候回想起来,好像大脑就关闭了,不再思考,然后就找不到bug就很急,越急越不思考,然后就会浪费很多时间。
其次就是代码逻辑是否清晰,如果的清晰逻辑的代码那么出bug会很容易看出来,并且修bug也非常容易,如果逻辑不清楚,修bug会不断增加补丁,然后的逻辑越来越乱,越来越恶心,找到bug也越来越难,拿高分也就变成了不可能,所以一开始写的代码就要力求逻辑清晰,即使会有高的时间复杂度。
还有一个事情,就是做第三题做多了,就想必须要用到map索引优化时间复杂度,有时候其实是没必要的,就比如这题,没必要用map,用来反而更复杂,不用也不会超出时间复杂度。
思路
一共分为三部分
第一部分是接受包然后检查是否要处理
第二部分是接受DIS包并发送OFR包
第三部分是接受REQ包并发送的ACK和NAK包
遇到的问题(一些逻辑不清晰导致的问题)
- 首先一开始没有想清楚要用的数据结构
//定义了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;
}
然后这个错误找了很久很久找到,可见逻辑清晰多么重要
改了之后
- 其次就是为了节省那一点点时间复杂度,就把遍历更新状态和遍历查找放在了一起,这样的逻辑很复杂,不清晰,应该分开做的。
不分开做导致req处理req的时候没有更新状态,只有接收到DIS报文的时候才更新,这样是有问题的,所以以后不要用那一点点小聪明想要减少时间复杂度,是不可行的,并且还可能导致bug找不到,正确的是先清晰的写,后续再优化。
- 还有判断超时时刻的出现问题,搞混了变量名的意义
在写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分
- 最后还是因为使用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;
}