网易雷火笔试20240428

三小时四道题。游戏服务端工程师。

A: 100%

签到题。

模拟。

B: 82%

输入:n个任务,m天,n个任务的value和截止日期limit,m天中每天发放多少张券。一张券可以完成一个任务。

输出:最多能获得多少value。

贪心。

笔试后完善的代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool cmp(const pair<int, int> &a, const pair<int, int> &b) {
    // 2. value相同时,日期大的排前面
    // why? 获得一个相同的value,使用后面发的券更“优惠”(前面的券能cover的任务范围更大)
    if (a.first == b.first)
        return a.second < b.second; 
    // 1. value大的排前面
    return a.first > b.first;       
}

int main() {
    int n, m;       // m, n <= 1e6
    cin >> n >> m;
    vector<pair<int, int>> tasks;
    for (int i = 0; i < n; ++i) {
        int value, limit;
        cin >> value >> limit;
        tasks.push_back({value, limit});
    }
    sort(tasks.begin(), tasks.end(), cmp);

    vector<int> tickets(m + 1);
    for (int i = 1; i <= m; ++i) { // 第i天
        cin >> tickets[i];
    }

    // 贪心算法,先把分数最高的任务(同分数以日期最高排序)和离截止日期最近的券匹配 
    long long ans = 0;
    int start = 1; // start之前没有券了
    for (int i = 0; i < tasks.size() && start <= m; ++i) {
        int value = tasks[i].first, day = min(tasks[i].second, m);

		// 极端情况下,每次都要遍历 m 次,这样就会超时。
		// 考虑用map<天数,券数>存储tickets,删除券数为0的元素。
        while (day >= start && tickets[day] == 0) --day;
        if (day >= start) {
            --tickets[day];
            ans += value;
        }
        else
            start = tasks[i].second + 1;
    }
    cout << ans << endl;
    return 0;
}

/*
4 3
3 1
4 2
5 3
6 4
1
1
1
*/

C: 100%

PI和老虎要离开无人岛去漂流,出发前要准备食物和水。PI每天需要1份食物和2份水,老虎每天需要2份食物和1份水。船上的体积为x,食物n份,水m份,n + 3m <= x。PI和老虎都不能中断饮食,PI在断食后Q天死亡,老虎在断食后P天吃掉PI。

输入x、P、Q,输出PI最久能存活的天数。

#include <bits/stdc++.h>
using namespace std;

int main()
{   
    int x, P, Q;
    cin >> x >> P >> Q;
    // pi吃一天需要1+3*2=7
    // 老虎吃一天需要1*2+3=5
    // 两者都吃一天需要12
    long long ans = 0;

    int diffDay = abs(P - Q), supply = 7;
    if (P < Q)
        supply = 5;
    if (x < diffDay * supply)
        ans = x / supply + min(P, Q);
    else
        ans = (x - diffDay * supply) / 12 + max(P, Q);

    // if (P > Q) {
    //     if (x < (P - Q) * 7) {
    //         ans = x / 7 + Q;
    //     }
    //     else {
    //         x -= (P - Q) * 7;
    //         ans = x / 12 + P;
    //     }
    // }
    // else {
    //     if (x < (Q - P) * 5) {
    //         ans = x / 5 + P;
    //     }
    //     else {
    //         x -= (P - Q) * 5;
    //         ans = x / 12 + Q;
    //     }
    // }

    return 0;
}

D: 26%

n个量子台(每个量子台只能踏足一次),m个双向传送门(传送一次需要承受一定伤害w)。从 s 出发,到 e 取钥匙,然后到 t 回到现实世界。

如果能回到现实世界,输出最小的承受伤害;否则输出-1。

改善思路:最短路路径一定完整包含一条 s->e 最短,或者 e->t 最短(未证明)。实现时,分别找出 s->e(e->t)的最短路(可能不止一条),然后再找对应剩余图中的 e->t(e->s)的最短路,遍历这些组合。

不ac的代码(错误原因:只保存了到达某个点的最小距离,但最小不一定最好(路径不一样,对后续有影响),而且可能有多个最小):

#include <iostream>
#include <tuple>
#include <queue>
#include <vector>
using namespace std;

int main() {
    // 从 s 出发,到 e 取钥匙,然后到 t 回到现实世界
    // 每个量子台只能踏足一次
    int n, m, s, e, t;
    cin >> n >> m >> s >> e >> t;

    vector<vector<pair<int, int>>> edges(n + 1);
    for (int i = 0; i < m; ++i) {
        int u, v, w;
        cin >> u >> v >> w; // u,v ∈ [1, n]
        edges[u].push_back({v, w});
        edges[v].push_back({u, w});
    }

    // st[i]表示到达点i承受的(最小)伤害,-1表示还没到达
    // st[i][0]未经过e st[i][1]经过e 
    vector<vector<long long>> st(n + 1, vector<long long>(2, -1));
    queue<tuple<int, long long, vector<bool>>> q; // <当前到达的量子台,已承受的伤害,vis数组>
    st[s][0] = 0;
    vector<bool> vis(n + 1, false);
    vis[s] = true;
    q.push({s, 0, vis});
    while (!q.empty()) {
        auto tu = q.front(); q.pop();
        int pos = get<0>(tu);
        long long ww = get<1>(tu);

        for (auto x : edges[pos]) {
            vector<bool> v = get<2>(tu);
            int nextPos = x.first;
            if (v[nextPos]) continue;
            v[nextPos] = true;
            
            if (!v[e] && (st[nextPos][0] == -1 || ww + x.second < st[nextPos][0])) {
                st[nextPos][0] = ww + x.second;
                q.push({nextPos, st[nextPos][0], v});
            }
            if (v[e] && (st[nextPos][1] == -1 || ww + x.second < st[nextPos][1])) {
                st[nextPos][1] = ww + x.second;
                q.push({nextPos, st[nextPos][1], v});
            }
        }
    }
    cout << st[t][1] << endl;
    return 0;
}

/*
5 7 1 4 5
1 2 5
1 3 1
4 2 6
5 4 14
3 4 2
1 5 6
5 3 3
*/

全部评论
大佬有没有可能出一个第一题的代码😣我第二题第三题都A了,第四题30%,唯独第一个签到题只有28.3%,而且一直检查不出来错误
1 回复
分享
发布于 04-29 13:52 香港
牛逼
点赞 回复
分享
发布于 04-28 18:52 广东
滴滴
校招火热招聘中
官网直投
感觉先找了s->e的最短路后在剩余图里找好像有可能找不到最优路径?比如例子里会找到1->3->4最短,路径长度是3,然后剩余图只能找到4->5,路径长度是14,这样总长度是17,而最优解是1->2->4->3->5是16. 还是说两个顺序都找一遍取较小就一定能找到?
点赞 回复
分享
发布于 04-28 20:17 广东
第二题应该还包括没券的时候需要玩家自己做任务的逻辑吧 而且我记得第三题原题好像是食物够的话老虎和PI必须都吃 不能主动让它们断食
点赞 回复
分享
发布于 04-29 11:20 美国
前 3 道 a 了,第四道 饿了去吃饭了没写完,我刚的思路是找到所有与 中间点的变,然后求经过这些边的最短路径,最后比较最小的(3 道应该够吧)
点赞 回复
分享
发布于 04-30 00:17 湖北
第四题正解个人感觉是费用流,感觉挺夸张的,能不带板子码这个都是高手。
点赞 回复
分享
发布于 05-12 04:28 辽宁

相关推荐

3 14 评论
分享
牛客网
牛客企业服务