网易雷火 4.22 笔试题解 【仅限于前3题】

事先声明,因为题目3没能在笔试时间内解出。所以个人也只是2题选手而已。【感觉凉了

另外有没有大佬解出了第四题,能交流一下第四题的解法吗?

题目1 消灭敌人数量

数学运算。遍历所有敌人节点,计算当前节点到黑洞中心的距离是否小于等于黑洞半径即可。

最后,返回所有满足条件的节点的总数即可。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>


using namespace std;

int main()
{
    int N;
    double R;
    cin >> N >> R;
    vector<vector<double>> bodys(N,vector<double>(3,0));
    for(int i=0;i<N;i++) cin >> bodys[i][0] >> bodys[i][1] >> bodys[i][2];
    double c_x,c_y,c_z;
    cin >> c_x >> c_y >> c_z;
    int result = 0;
    for(int i=0;i<N;i++)
    {
        double now_len = pow(pow(bodys[i][0] - c_x,2) + pow(bodys[i][1] - c_y,2) + pow(bodys[i][2] - c_z,2),0.5);
        if(now_len <= R) result++;
    }
    cout << result << endl;
    return 0;
}

题目2 飞机问题

模拟思路。

其实可以近似看作是操作系统里的PV问题? 具体可以使用懒处理思路:当无人机群返回时,如果当前无人机群前置无人机群还未返回,反正此时返回无人机群所得到的无人机也是处于休眠状态,不如先将其标记,等到前置无人机群都已经返回时再一并处理。同时,还有一点需要注意,虽然题目中没有明确说明,但从对测试案例的测试过程中发现。但返回请求的返回无人机群的操作结束后【在处理派出无人机请求等待队列前】,如果此时条件满足需要进行基地升级,则必须进行基地升级操作。【否则可能导致部分测试用例无法通过】

解题步骤如下【其实可以直接边看代码边看注释,个人自我感觉这题的注释还是写的比较详细的】:

1.构建run_struct结构题存储每一次请求对应的无人机群的相关信息,构建plan_run类用于处理题目逻辑

2.构建 sleep_nums 【但其实个人后续代码未使用】,run_nums,can_nums,total 记录当前基地内关于无人机的各项信息

3.建立 return_wait 队列存储等待返回的无人机群的相关信息,建立 run_wait 队列存储等待请求派遣的无人机群的相关信息,建立id_set 集合存储当前已经请求返回但前置无人机群还未返回的无人机群id。【以便后续懒处理】

4.构建 up_total() 函数以实现基地的升级操作,构建 new_run() 函数及其具体逻辑以实现对派出无人机群请求的操作,建立 now_return() 函数及其具体逻辑以实现对请求无人机群返回指令的操作。

5.构建main()函数内容,以实现格式化输入输出。

#include <iostream>
#include <queue>
#include <vector>
#include <unordered_set>


using namespace std;

typedef struct
{
    int nums;
    int id;
}run_struct;


class plan_run
{
private:
    int sleep_nums = 0; // 当前休眠的无人机数
    int run_nums = 0; // 当前正在执行任务的无人机数
    int can_nums; // 当前可以使用的无人机数
    int total; // 当前等级下,基地的无人机总数
public:
    queue<run_struct> run_wait; // 派出无人机请求等待队列
    queue<run_struct> return_wait; // 当前派出待返回的无人机的队列
    unordered_set<int> id_set; // 目前已经使用指令申请返回的无人机编号集合
    // 构造函数
    plan_run(int C):total(C){ can_nums = total; };
    // 功能函数 返回值均为当前请求后新派出的无人机数目

    // 升级
    void up_total(int m)
    {
        total = m;
        can_nums = total;
    }

    // 派出
    int new_run(int id,int m)
    {
        run_struct run_temp;
        run_temp.id = id;
        run_temp.nums = m;
        if(m > total && total == can_nums) this->up_total(m);
        if(m <= can_nums)
        {
            // 执行派遣 将请求放入等待返回队列末尾
            can_nums -= m;
            run_nums += m;
            return_wait.push(run_temp);
            return m;
        }
        else
        {
            // 当前可用无人机数不足,将请求放入等待队列末尾
            run_wait.push(run_temp);
            return 0;
        }
    }

    // 返回
    int now_return(int id)
    {
        // 表示当前所要返回的无人机群为最早未返回的无人机群
        if(id == return_wait.front().id)
        {
            run_struct now_temp = return_wait.front();
            return_wait.pop();
            can_nums += now_temp.nums;
            run_nums -= now_temp.nums;
            // 如果 已有的请求返回的后续无人机序列编号 不为空 则按时间顺序返回
            if(!id_set.empty())
            {
                while(!id_set.empty() && !return_wait.empty() && id_set.find(return_wait.front().id) != id_set.end())
                {
                    now_temp = return_wait.front();
                    return_wait.pop();
                    can_nums += now_temp.nums;
                    run_nums -= now_temp.nums;
                    id_set.erase(now_temp.id);
                }
            }
        }
        else
        {
            id_set.insert(id);
        }

        // 是否需要更新升级 再详细阅读题目后再考虑编写 确认需要升级
        if(!run_wait.empty() && can_nums < run_wait.front().nums && can_nums == total) this->up_total(run_wait.front().nums);

        // 处理派出请求等待队列
        int now_run_nums = 0;
        // 只要当前的无人机数超过派出请求等待队列队首的请求数量 则进行派遣
        while(!run_wait.empty() && can_nums >= run_wait.front().nums)
        {
            run_struct now_run_temp;
            now_run_temp = run_wait.front();
            run_wait.pop();
            can_nums -= now_run_temp.nums;
            run_nums += now_run_temp.nums;
            now_run_nums += now_run_temp.nums;
            return_wait.push(now_run_temp);
        }
        // 返回当前新派出的无人机数量
        return now_run_nums;
    }

};



int main()
{
    int C,N;
    cin >> C >> N;
    plan_run A(C);
    for(int i=0;i<N;i++)
    {
        int now_id,now_m;
        cin >> now_id >> now_m;
        if(now_id == -1)
        {
            cout << A.now_return(now_m) << endl;
        }
        else
        {
            cout << A.new_run(now_id,now_m) << endl;
        }
    }

    return 0;
}

题目3 炉石传说 【因为没想到会是输入格式问题导致段错误,导致个人没能在笔试时间内做出来······】

具体考虑回溯思路。

需要注意的是,如果当前敌方存在存活的嘲讽随从,则只针对嘲讽随从进行回溯遍历。而在当前可用随从攻击次数结束之后,在使用亵渎法术时,现存的圣盾可以当成一点额外的生命值处理。同时,如果使用亵渎法术的花费cost超过了8,则这时候直接使用法术B更为合理,具体判断公式即为:min(cost,8);

具体解题过程如下:

1.建立Game_Manager 类来处理游戏逻辑,建立man_struct结构题存储随从数据

2.建立init()函数来通过输入的数据初始化Game_Manager类 M对象

3.建立Attack()和Attack_Down()函数来实现随从攻击对当前游戏状态的变化,以及后续回溯时的状态复原。

4.建立super_A() 函数来实现法术A的递归使用【就是题目中的亵渎法术】

5.编写run_main()和run_Attack()函数来对回溯算法进行整体实现。

6.编写main()函数中内容,进行标准格式化输入输出【个人就是没想到当初段错误是这里的输入错误导致的】

#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

// 创建随从结构体 用于保存随从的数据

typedef struct
{
    int attack;
    int life;
    int attack_nums = 0;
    int cf = 0;
    int sd = 0;
    bool sd_used = false;
}man_struct;


// 创建游戏管理员类 通过该类进行游戏交互

class GameManager
{
private:
    vector<man_struct> A_man_list; // 玩家A的随从队列
    vector<man_struct> B_man_list; // 玩家B的随从队列
public:
    // 功能函数
    // 随从攻击
    void Attack(int id_A,int id_B)
    {
        if(A_man_list[id_A].sd == 0 || B_man_list[id_B].attack == 0) A_man_list[id_A].life -= B_man_list[id_B].attack;
        else
        {
            A_man_list[id_A].sd = 0;
            A_man_list[id_A].sd_used = true;
        }
        if(B_man_list[id_B].sd == 0 || A_man_list[id_A].attack == 0) B_man_list[id_B].life -= A_man_list[id_A].attack;
        else
        {
            B_man_list[id_B].sd = 0;
            B_man_list[id_B].sd_used = true;
        }
        A_man_list[id_A].attack_nums++;
        B_man_list[id_B].attack_nums++;
    }

    void Attack_Down(int id_A,int id_B)
    {
        // 当当前随从的被打击数不为1时,证明不是这一次导致的圣盾消失,故只回溯生命状态
        if(A_man_list[id_A].sd_used == true && A_man_list[id_A].attack_nums == 1)
        {
            A_man_list[id_A].sd = 1;
            A_man_list[id_A].sd_used = false;
        }
        else A_man_list[id_A].life += B_man_list[id_B].attack;
        if(B_man_list[id_B].sd_used == true && B_man_list[id_B].attack_nums == 1)
        {
            B_man_list[id_B].sd = 1;
            B_man_list[id_B].sd_used = false;
        }
        else B_man_list[id_B].life += A_man_list[id_A].attack;
        A_man_list[id_A].attack_nums--;
        B_man_list[id_B].attack_nums--;
    }
    // 法术A
    void super_A(vector<int>& now_lifes)
    {
        int now_dead = 0;
        for(int i=0;i<now_lifes.size();i++)
        {
            if(now_lifes[i] > 0)
            {
                now_lifes[i]--;
                if(now_lifes[i] <= 0) now_dead++;
            }
        }
        if(now_dead > 0) super_A(now_lifes);
    }

    int sum_list(vector<int>& nums)
    {
        int sum = 0;
        for(int i=0;i<nums.size();i++) sum += nums[i];
        return sum;
    }

    //寻找当前最优解 回溯
    int run_Attack(int do_max,int now_do,vector<int>& used)
    {
        int cost = 0;
        vector<int> now_lifes;
        // 计算当前使用法术的费用情况
        // 同时,对于某些特殊的情况 不一定当前的随从全部攻击完后,其结果就最优,故在此对每一次回溯均进行一次法术消耗的测试
        for(int i=0;i<A_man_list.size();i++)
        {
            if(A_man_list[i].life > 0) now_lifes.push_back(A_man_list[i].life + A_man_list[i].sd);
        }
        for(int i=0;i<B_man_list.size();i++)
        {
            if(B_man_list[i].life > 0) now_lifes.push_back(B_man_list[i].life + B_man_list[i].sd);
        }
        while(sum_list(now_lifes) != 0)
        {
            super_A(now_lifes);
            cost += 2;
            // 当cost超过8时 此时无需再进行后续处理 直接使用法术B【cost 8】即可 也可以在 while 中判断
            if(cost >= 8) break;
        }
        // 当攻击次数超过限制 仅考虑使用法术的情况
        if(now_do >= do_max)
        {
            return min(cost,8);
        }
        // 还可以攻击时
        int result = min(cost,8);
        for(int i=0;i<B_man_list.size();i++)
        {
            if(used[i] == 1) continue;
            used[i] = 1;
            vector<int> cf_list;
            for(int j=0;j<A_man_list.size();j++)
            {
                if(A_man_list[j].life > 0 && A_man_list[j].cf == 1) cf_list.push_back(j);
            }
            if(!cf_list.empty())
            {
                for(int j = 0;j<cf_list.size();j++)
                {
                    this->Attack(cf_list[j],i);
                    result = min(result,this->run_Attack(do_max,now_do + 1,used));
                    this->Attack_Down(cf_list[j],i);
                }
            }
            else
            {
                for(int j=0;j<A_man_list.size();j++)
                {
                    if(A_man_list[j].life <= 0) continue;
                    this->Attack(j,i);
                    result = min(result,this->run_Attack(do_max,now_do + 1,used));
                    this->Attack_Down(j,i);
                }
            }
            used[i] = 0;
        }
        return result;
    }
    // 运行主函数
    int run_main()
    {
        vector<int> used(B_man_list.size(),0);
        int m = B_man_list.size();
        return run_Attack(min(2,m),0,used);
    }
    // init
    void init(int nums_A,string str_A,int nums_B,string str_B)
    {
        int now_A = 0,now_B = 0;
        while(nums_A--)
        {
            man_struct temp;
            while(str_A[now_A] != ' ')
            {
                if(str_A[now_A] == '(')
                {
                    temp.sd = 1;
                }
                else if(str_A[now_A] <= '9' && str_A[now_A] >= '0')
                {
                    int now_nums = 0;
                    if(str_A[now_A] == '1' && now_A+1 < str_A.length()-1 && str_A[now_A + 1] =='0')
                    {
                        now_nums = 10;
                    }
                    else now_nums = str_A[now_A] - '0';
                    if(now_A >0 && str_A[now_A - 1] == '/')
                    {
                        temp.life = now_nums;
                    }
                    else temp.attack = now_nums;
                    if(now_nums == 10) now_A++;
                }
                else if(str_A[now_A] == '!') temp.cf = 1;
                now_A++;
            }
            now_A++;
            //temp.total_life = temp.life;
            A_man_list.push_back(temp);
        }

        while(nums_B--)
        {
            man_struct temp;
            while(str_B[now_B] != ' ')
            {
                if(str_B[now_B] == '(')
                {
                    temp.sd = 1;
                }
                else if(str_B[now_B] <= '9' && str_B[now_B] >= '0')
                {
                    int now_nums = 0;
                    if(str_B[now_B] == '1' && now_B+1 < str_B.length()-1 && str_B[now_B + 1] =='0')
                    {
                        now_nums = 10;
                    }
                    else now_nums = str_B[now_B] - '0';
                    if(now_B >0 && str_B[now_B - 1] == '/')
                    {
                        temp.life = now_nums;
                    }
                    else temp.attack = now_nums;
                    if(now_nums == 10) now_B++;
                }
                else if(str_B[now_B] == '!') temp.cf = 1;
                now_B++;
            }
            now_B++;
            //temp.total_life = temp.life;
            B_man_list.push_back(temp);
        }
    }
};




int main()
{
    // 策略判断 因为是寻求cost花费最小 故优先使用随从攻击敌方随从 而后使用法术A 如果法术A使用四次以上 则直接使用法术B 单回合最大花销不会超过8

    int N;
    cin >> N;
    while(N--)
    {
        int nums_A,nums_B;
        string str_A = "",str_B = "";
        cin >> nums_A;
        for(int i=0;i<nums_A;i++)
        {
            string temp;
            cin >> temp;
            str_A += temp + ' ';
        }
        cin >> nums_B;
        for(int i=0;i<nums_B;i++)
        {
            string temp;
            cin >> temp;
            str_B += temp + ' ';
        }
        // 格式化输入测试 如有需要自行取消注释
        // cout << "str_A: " <<  str_A << endl;
        // cout << "str_B: " << str_B << endl;
        GameManager M;
        M.init(nums_A,str_A,nums_B,str_B);
        cout << M.run_main() << endl;
    }

    return 0;
}

#网易雷火后端笔试4.22##网易雷火##网易信息集散地##网易雷火游戏笔试#
全部评论
三四题有点离谱,第四题优化半天5%
1 回复 分享
发布于 2023-04-22 20:20 湖北
唉 第二题都不能ac的菜鸡
1 回复 分享
发布于 2023-04-22 20:22 四川
为什么感觉第三题攻击后的回溯有问题呢,如果两个怪先后攻击一个圣盾怪,第二次攻击回溯会导致圣盾怪的圣盾恢复,随后圣盾怪的血量恢复值是第一个怪的攻击力,感觉要加一个判定
点赞 回复 分享
发布于 2023-04-24 22:03 浙江
大佬第四题代码出来了的话,蹲蹲
点赞 回复 分享
发布于 2023-04-25 12:09 香港

相关推荐

预计下个星期就能开奖吧,哪位老哥来给个准信
华孝子爱信等:对接人上周说的是这周
点赞 评论 收藏
分享
11-15 17:19
湖南大学 Java
成果成果成果果:这是哪个公司的hr,这么离谱吗,我没见过用性别卡技术岗的,身边女性同学拿大厂offer的比比皆是
点赞 评论 收藏
分享
6 39 评论
分享
牛客网
牛客企业服务