CSP 202104-3 大模拟

3 DHCP服务器

因为是个大模拟,题目又臭又长还有点儿绕,解答本题要好好理解题意,按照题目要求来写。

题意

在这里插入图片描述
DHCP 数据报文的格式:

<发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
 string    string     DIS
              *       OFR
                      REQ
                      ACK
                      NAK

在这里插入图片描述
在这里插入图片描述

Round 1

代码按照题目给出的细节要求一步步进行即可,但是需要注意一些细节处理,例如条件之间的关系该用与还是或。
在这里插入图片描述
问题主要出现在这个地方:out给出的是过期的时刻,所以这里要判断 过期时间是否超过上下限

错误示例:
在这里插入图片描述
正确示例: 要注意是时刻,过期时刻out out-t 才是有效时间
在这里插入图片描述

Round 2

注意到:样例解释中的 第 13、14 个报文中,e 试图请求地址。此时地址池中已经没有处于“未分配”状态的地址了,但是有此前分配给 b 的地址 2 的状态是“过期”,因此把该地址重新分配给 e。 就可以发现 你忘记处理过期的地址池了。

根据:
在这里插入图片描述
在处理每条命令前,要处理一下过期的IP:
在这里插入图片描述
等会儿!!! 这里 过期时刻应该是 ip[i].out<=t 而不是刚刚好=!!!你要没发现的话 又该要debug很久了???你写啥呢???大模拟最重要的就是细节啊!!! 仔细点儿!!!

Round 3

进行了以上修改后,基本上可以得到比较好的结果了,如下结果基本正确,但最后一条命令没能读入处理???
在这里插入图片描述
此时得分只有40分,那么 为什么会提前终止了呢???

啊 笨蛋 让你乱用 break ,
在这里插入图片描述
因为这里有个 break ,刚好你第15个命令就走到了这里…然后break出读命令的循环了…
在这里插入图片描述
噗 改完这个bug还是只有60分…样例能过了,但肯定还存在其他没有考虑到的细节!!!

Round 4

噗噗…吐得一脸好血…
在这里插入图片描述
这里这里…在这里插入图片描述
debug de那么久…没发现是应该 ip[j].own==send 吗…之前写的是 ==recieve 啊老天鹅…这要不是对了一遍算法流程还真发现不了?

我还是太粗心了…

完整代码

//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1e4+5;
struct node{
    int state;// 0未分配 1待分配 2占用 3过期
    int out;//过期时刻
    string own;//占用者
}ip[maxn];
int main()
{
    int N,tdef,tmax,tmin,n;
    string H;
    cin>>N>>tdef>>tmax>>tmin>>H;
    for(int i=1;i<=N;i++)
    {
        ip[i].state=0;
        ip[i].out=0;
        ip[i].own="";
    } 
    cin>>n;
    for(int k=0;k<n;k++) 
    {   
        string send,receive,type;
        int address,t,out;
        //<收到报文时刻> <发送主机> <接收主机> <报文类型> <IP 地址> <过期时刻>
        cin>>t>>send>>receive>>type>>address>>out;
        //cout<<"y  "<<t<<endl;
        //cout<<"i "<<t<<" "<<send<<" "<<receive<<" "<<type<<" "<<address<<" "<<out<<endl;
        //cout<<"-!-"<<endl;
        //cout<<type<<endl;
        for(int i=1;i<=N;i++)//遍历所有IP
        {
            if(ip[i].state==1&&ip[i].out<=t) //如果过期时刻比当前时刻早
            {
                ip[i].state=0;
                ip[i].own="";
                ip[i].out=0;

            }else if(ip[i].state==2&&ip[i].out<=t)
            {
                ip[i].state=3;
                ip[i].out=0;
            }else if(ip[i].state==3||ip[i].state==0)
            {
                ip[i].out=0;
            }
        }

        if((receive!=H&&receive!="*")&&type!="REQ") // 同理 这里的也应该是&& 而且之前放错位置了!这个应该在第一个进行判断
            continue;
        
        //这样也是ok的
        if(type!="REQ"&&type!="DIS") //你怎么能在这用||呢?这样满足第一个条件就算是DIS也会continuecontinue;
        //if(type=="REQ"||type=="DIS")
        //{ 
        if((receive=="*"&&type!="DIS")||(receive==H&&type=="DIS"))
            continue;
        
        if(type=="DIS")
        {
            int rip=-1;
            for(int j=1;j<=N;j++)
            {
                if(ip[j].state&&ip[j].own==send) // 只要不是0未分配状态,就都有占用者
                {
                    rip=j;
                    break;
                }    
            }
            if(rip==-1) // 若没有,则选取最小的状态为未分配的 IP 地址;
            {
                for(int j=1;j<=N;j++)
                {
                    if(!ip[j].state)
                    {
                        rip=j;
                        break;
                    }
                }
            }
            if(rip==-1) // 若没有,则选取最小的状态为过期的 IP 地址;
            {
                for(int j=1;j<=N;j++)
                {
                    if(ip[j].state==3)
                    {
                        rip=j;
                        break;
                    }
                }
            }
            if(rip!=-1) // 找到了可用ip,可继续处理
            {
                ip[rip].state=1;
                ip[rip].own=send;
                if(out==0)
                    ip[rip].out=t+tdef;
                else if(out-t>=tmax)
                    ip[rip].out=t+tmax;
                else if(out-t<=tmin)
                    ip[rip].out=t+tmin;
                else 
                    ip[rip].out=out;
                cout<<H<<" "<<send<<" OFR "<<rip<<" "<<ip[rip].out<<endl;
            }
            //if(rip==-1)
            //cout<<"not enough"<<endl;
        }else if(type=="REQ")
        {
            if(receive!=H) //发给非本服务器的 不予应答
            {
                for(int j=1;j<=N;j++)
                {
                    if(ip[j].own==send&&ip[j].state==1)
                    {
                        ip[j].state=0;
                        ip[j].own="";
                        ip[j].out=0;
                    }
                }
            }else //注意后半部分要包在else{
                //if(!(address>=1&&address<=N&&ip[address].own==send))
                if(address<1||address>N||ip[address].own!=send)
                {
                    cout<<H<<" "<<send<<" NAK "<<address<<" 0"<<endl;
                }else{
                    ip[address].state=2;
                    if(out==0)
                        ip[address].out=t+tdef;
                    else if(out-t>tmax) // ???你脑子瓦特啦 out-t 才是有效时间,out给出的是过期时刻
                        ip[address].out=t+tmax;
                    else if(out-t<tmin)
                        ip[address].out=t+tmin;
                    else
                        ip[address].out=out;
                    cout<<H<<" "<<send<<" ACK "<<address<<" "<<ip[address].out<<endl;
                }  
            }
        }
        //}
    }
    //cout<<"out"<<endl;
    return 0;
}

总结

  大模拟需要的就是耐心和仔细,其实并不难,但是如果不注意的话,写bug的概率会比较大,就像笔者上面干的蠢事一样…2333
  其实可以不看原理部分,而是直接从实施细节开始就好了,前面都没啥用2333,但当然 你要知道一点DHCP工作原理啦…当然不知道其实也可以,一步步按照细节说的去写流程代码就好啦。
  最后 还是 细节 细节 细节!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值