看了一波y总的视频以后,做出来了这辈子第一个模拟题呜呜呜,我太菜了
//这种模拟竟然属于比较简单的模拟???
//直接按照顺序敲就可以了,其实也不不是很难,主要是自己之前没有做过
//而且压根没静下心想一下,把程序想象成服务器就行了,明显需要维护的就是一个ip地址池
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10010;//所以时间复杂度应不超过n方
int n, m, t_def, t_max, t_min;//ip地址个数, 请求个数,分配个客户端的ip地址的默认过期时间长度
//最长和最短过期时间
string h;//主机名称
struct IP
{
int state; // 0:未分配, 1:待分配 2:占用 3:过期
int t;//过期时间
string owner;
}ip[N];
void update_ips_state(int tc)
{
//对所有ip更新
for(int i=1; i<=n; i++)
{
//如果ip的过期时刻大于0,并且过期了
if(ip[i].t && ip[i].t<= tc)
{
//如果待分配,则状态变成未分配,且占用者清空,过期时刻清零
if(ip[i].state == 1)
{
ip[i].state=0;
ip[i].owner="";
ip[i].t=0;
}
//否则该地址的状态会由占用自动变为过期,且过期时刻清零。
else
{
ip[i].state=3;
ip[i].t=0;
}
}
}
}
//选取特定状态的ip
int get_ip_by_state(int state)
{
for(int i=1; i<=n; i++)
if(ip[i].state == state)
return i;
return 0; //否则返回分配失败
}
//通过client找一下有没有用过的ip
int get_ip_by_owner(string client)
{
for(int i=1; i<=n; i++)
if(ip[i].owner == client)
return i;
return 0;
}
int main()
{
cin>>n>>t_def>>t_max>>t_min>>h;
cin>>m;
while(m--)
{
int tc;//收到报文的时间
string client, server, type;
int id, te;//<发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
cin>>tc>>client>>server>>type>>id>>te;
//按照处理细节依次处理
//三种情况都不处理
if(server!=h && server!="*")
{
if(type != "REQ") continue;
}
if(type != "DIS" && type!="REQ") continue;
//确实,发*一定对应dis, 给服务器发一定不对应dIS
if((server == "*" && type != "DIS") || (server == h && type == "DIS")) continue;
//然后更新一下ip地址池的状态,确实,每次处理一个新的报文,都要更新状态
update_ips_state(tc);//传入当前时刻
//处理dis报文
if(type == "DIS")
{
//检查是否有占用者为发送主机的 IP 地址:
//若有,则选取该 IP 地址;
int k=get_ip_by_owner(client);
//若没有,则选取最小的状态为未分配的 IP 地址;
if(!k) k=get_ip_by_state(0);//0是未分配
// 若没有,则选取最小的状态为过期的 IP 地址;
if(!k) k=get_ip_by_state(3);//过期为3
// 若没有,则不处理该报文,处理结束
if(!k) continue;
//当分配到ip地址以后
// 将该 IP 地址状态设置为待分配,占用者设置为发送主机;
ip[k].state=1, ip[k].owner=client;
// 若报文中过期时刻为 0 ,则设置过期时刻为 t+Tdef;
if(!te) ip[k].t=tc+t_def;
// 否则根据报文中的过期时刻和收到报文的时刻计算过期时间,
// 判断是否超过上下限:若没有超过,则设置过期时刻为报文中
// 的过期时刻;否则则根据超限情况设置为允许的最早或最晚的过期时刻;
else
{
int t= te- tc;//想使用的时间长度
t=max(t, t_min), t=min(t, t_max);
//t既不能小于最低时间,也不能超过最长时间
ip[k].t=tc+t;
}
//应该发送报文了
cout<< h << " " << client << ' ' <<"OFR" <<' ' << k << ' ' <<ip[k].t <<endl;
}
//处理request请求
else
{
//如果接受者不是本机
if (server != h)
{
// 到占用者为发送主机的所有 IP 地址,对于其中状态为待分配的,将其状态设置为未分配,并清空其占用者,清零其过期时刻,处理结束;
for(int i=1; i<=n; i++)
{
if(ip[i].owner == client && ip[i].state == 1)
{
ip[i].state = 0;
ip[i].owner= "";
ip[i].t=0;
}
}
continue;
}
// 检查报文中的 IP 地址是否在地址池内,若不是,则向发送主机发送 Nak 报文,处理结束;
if(!(id>=1 && id<=n && ip[id].owner == client))
cout << h << ' ' << client << ' ' <<"NAK" <<" " << id <<' '<<0 <<endl;
//如果在地址池内
else
{
// 无论该 IP 地址的状态为何,将该 IP 地址的状态设置为占用;
ip[id].state=2;
// 与 Discover 报文相同的方法,设置 IP 地址的过期时刻;
if(!te) ip[id].t=tc+t_def;
else
{
int t= te- tc;//想使用的时间长度
t=max(t, t_min), t=min(t, t_max);
//t既不能小于最低时间,也不能超过最长时间
ip[id].t=tc+t;
}
//应该发送报文了
cout<< h <<' '<<client <<' '<<"ACK" <<' '<<id <<' ' <<ip[id].t <<endl;
}
}
}
return 0;
}