第三题也不是不能写。全看状态。这题我尽力辽。。不过只过了一半。寄!听天由命。不写了
202104-3 | |
试题名称: | DHCP服务器 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 试题背景动态主机配置协议(Dynamic Host Configuration Protocol, DHCP)是一种自动为网络客户端分配 IP 地址的网络协议。当支持该协议的计算机刚刚接入网络时,它可以启动一个 DHCP 客户端程序。后者可以通过一定的网络报文交互,从 DHCP 服务器上获得 IP 地址等网络配置参数,从而能够在用户不干预的情况下,自动完成对计算机的网络设置,方便用户连接网络。DHCP 协议的工作过程如下:
在本题目中,你需要理解 DHCP 协议的工作过程,并按照题目的要求实现一个简单的 DHCP 服务器。 问题描述报文格式为了便于实现,我们简化地规定 DHCP 数据报文的格式如下: None DHCP 数据报文的各个部分由空格分隔,其各个部分的定义如下:
例如下列都是合法的 DHCP 数据报文: None 服务器配置为了 DHCP 服务器能够正确分配 IP 地址,DHCP 需要接受如下配置:
分配策略当客户端请求 IP 地址时,首先检查此前是否给该客户端分配过 IP 地址,且该 IP 地址在此后没有被分配给其它客户端。如果是这样的情况,则直接将 IP 地址分配给它,否则, 实现细节在 DHCP 启动时,首先初始化 IP 地址池,将所有地址设置状态为未分配,占用者为空,并清零过期时刻。 对于收到的报文,设其收到的时刻为 t。处理细节如下:
对于 Discover 报文,按照下述方法处理:
对于 Request 报文,按照下述方法处理:
上述处理过程中,地址池中地址的状态的变化可以概括为如下图所示的状态转移图。为了简洁,该图中没有涵盖需要回复 Nak 报文的情况。 输入格式输入的第一行包含用空格分隔的四个正整数和一个字符串,分别是:N、Tdef、Tmax、Tmin 和 H,保证 Tmin≤Tdef≤Tmax。 输入的第二行是一个正整数 n,表示收到了 n 个报文。 输入接下来有 n 行,第 (i+2) 行有空格分隔的正整数 ti 和约定格式的报文 Pi。表示收到的第 i 个报文是在 ti 时刻收到的,报文内容是 Pi。保证 ti<ti+1。 输出格式输出有若干行,每行是一个约定格式的报文。依次输出 DHCP 服务器发送的报文。 样例输入 Data 样例输出 Data 样例说明输入第一行,分别设置了 DHCP 的相关参数,并收到了 16 个报文。 第 1 个报文和第 2 个报文是客户端 第 3 个报文不符合 Discover 报文的要求,不做任何处理。 第 4 个报文 第 5 个报文中,Request 报文不符合接收主机是 DHCP 服务器本机的要求,因此不做任何处理。 第 6 个报文是 第 7 个报文中,过期时刻 11 小于最短过期时间,因此返回的过期时刻是 12。虽然此时为 第 9、10 两个报文中,为 第 11 个报文中, 第 12 个报文中, 第 13、14 个报文中, 第 15 个报文中, 第 16 个报文中, 样例输入 Data 样例输出 Data 样例说明在本样例中,DHCP 服务器一共收到了 6 个报文,处理情况如下: 第 1 个报文不是 DHCP 服务器需要处理的报文,因此不回复任何报文。 第 2 个报文中, 第 3 个报文中, 第 4 个报文中, 第 5、6 个报文中, 评测用例规模与约定对于 20% 的数据,有 N≤200,且 n≤N,且输入仅含 Discover 报文,且 t<Tmin; 对于 50% 的数据,有 N≤200,且 n≤N,且 t<Tmin,且报文的接收主机或为本机,或为 对于 70% 的数据,有 N≤1000,且 n≤N,且报文的接收主机或为本机,或为 对于 100% 的数据,有 N≤10000,且 n≤10000,主机名的长度不超过 20,且 t,Tmin,Tdefault,Tmax≤109,输入的报文格式符合题目要求,且数字不超过 109。 |
#include <bits/stdc++.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct bao_wen{
int t;
string fa_song;
string jie_shou;
string type;
int ip;
int guo_qi;
};
struct IP{
int guo_qi=0;
int zhuang_tai=0;//0表示未占用,1表示待分配,2表示占用,3表示过期
string name="null";
};
int main(int argc, char** argv)
{
int N,Tdef,Tmax,Tmin;
string H;
cin>>N>>Tdef>>Tmax>>Tmin>>H;
map<int,IP> I;
for(int i=0;i<N;i++){
IP temp;
I.insert(pair<int,IP>(i+1,temp));
}
int n;cin>>n;
for(int k=0;k<n;k++){
bao_wen x;
cin>>x.t>>x.fa_song>>x.jie_shou>>x.type>>x.ip>>x.guo_qi;
if(x.jie_shou!="dhcp"&&x.jie_shou!="*"){
if(x.type!="REQ")continue;//判断接收主机是否为本机,或者为 *,若不是,则判断类型是否为 Request,若不是,则不处理
}
if(x.type!="REQ"&&x.type!="DIS"){
continue;//若类型不是 Discover、Request 之一,则不处理
}
if((x.jie_shou=="*"&&x.type!="DIS")||(x.jie_shou=="dhcp"&&x.type=="Discover")){
continue;//若接收主机为 *,但类型不是 Discover,或接收主机是本机,但类型是 Discover,则不处理
}
map<int,IP>::iterator itt;
for(itt=I.begin();itt!=I.end();itt++){
if(itt->second.guo_qi<=x.t){
IP tempp;
if(itt->second.zhuang_tai==1){
int temp=itt->first;//在到达该过期时刻时,若该地址的状态是待分配,则该地址的状态会自动变为未分配,且占用者清空,过期时刻清零
I[temp]=tempp;
}
else if(itt->second.zhuang_tai==2){
tempp.zhuang_tai=3;//否则该地址的状态会由占用自动变为过期,且过期时刻清零
tempp.name=itt->second.name;
int temp=itt->first;
I[temp]=tempp;
}
}
}
if(x.type=="DIS"){
map<int,IP>::iterator it;
int ip_temp=0;
for(it=I.begin();it!=I.end();it++){//有占用者为发送主机的 IP 地址
if(it->second.name==x.fa_song){
ip_temp=it->first;
break;
}
}
if(ip_temp==0){//若没有,则选取最小的状态为未分配的 IP 地址
for(it=I.begin();it!=I.end();it++){
if(it->second.zhuang_tai==0){
ip_temp=it->first;
break;
}
}
}
if(ip_temp==0){//若没有,则选取最小的状态为过期的 IP 地址
for(it=I.begin();it!=I.end();it++){
if(it->second.zhuang_tai==3){
ip_temp=it->first;
break;
}
}
}
if(ip_temp==0)continue;//还没有,处理结束
IP ip_tempp;
ip_tempp.name=x.fa_song;
ip_tempp.zhuang_tai=1;//设置为待分配
if(x.guo_qi==0) ip_tempp.guo_qi=x.t+Tdef;
else {
int min=x.t+Tmin;
int max=x.t+Tmax;
if(x.guo_qi<min)x.guo_qi=min;//超过下限
else if(x.guo_qi>max)x.guo_qi=max;//超过上限
ip_tempp.guo_qi=x.guo_qi;
}
I[ip_temp]=ip_tempp;
cout<<"dhcp"<<" "<<x.fa_song<<" "<<"OFR"<<" "<<ip_temp<<" "<<ip_tempp.guo_qi<<endl;
}
else if(x.type=="REQ"){
if(x.jie_shou!="dhcp"){//接收主机不是为本机
map<int,IP>::iterator it;
for(it=I.begin();it!=I.end();it++){
if(it->second.name==x.fa_song){
it->second.zhuang_tai=0;
it->second.name="null";
it->second.guo_qi=0;
}
}
continue;
}
if(x.ip>=1&&x.ip<=N){//报文中的 IP 地址是否在地址池内
IP ip_tempp=I[x.ip];
if(ip_tempp.name!=x.fa_song){
cout<<"dhcp"<<" "<<x.fa_song<<" "<<"NAK"<<" "<<x.ip<<" "<<"0"<<endl;
}
else{
ip_tempp.zhuang_tai=2;
int min=x.t+Tmin;
int max=x.t+Tmax;
if(x.guo_qi<min)x.guo_qi=min;//超过下限
else if(x.guo_qi>max)x.guo_qi=max;//超过上限
ip_tempp.guo_qi=x.guo_qi;
I[x.ip]=ip_tempp;
cout<<"dhcp"<<" "<<x.fa_song<<" "<<"ACK"<<" "<<x.ip<<" "<<x.guo_qi<<endl;
}
}
}
}
return 0;
}
/*/
map<int,IP>::iterator it;
for(it=I.begin();it!=I.end();it++){
cout<<it->first<<" "<<it->second.name<<" "<<it->second.zhuang_tai<<" "<<it->second.guo_qi<<endl;
}
/*/