华为实验室研究岗社招机试题

华为社招机试,面得实验室的研究岗,hr说是ACM难度的,诚不我欺

第一题

方法:最开始没有想到什么好方法,于是写个DFS,通过0%,后来加了一个最短路,没来得及测试。但是单独求最短路并没有考虑有多条最短路的情况。

点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<queue>
using namespace std;

struct Edge {
    int next, w;
};

const int maxn = 100+10;
int n, m, t, s, e;
int times[maxn], vals[maxn];
vector<Edge>edges[maxn];

Edge prenode[maxn], nxt[maxn];
void dijsktra(int n, int s, int e) {

    vector<int> dist(n+1, INT_MAX);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    dist[s] = 0;
    pq.push({0, s});
    while(!pq.empty()) {
        int u = pq.top().second, d = pq.top().first;
        pq.pop();
        if(dist[u] < d) continue;   // 剪枝,已经求得更小的了
        if(u == e) break;
        for(auto& node : edges[u]) {
            int v = node.next, d = node.w;
            if(dist[v] > dist[u] + d) {
                dist[v] = dist[u] + d;
                prenode[v] = {u, d};
                pq.push({dist[v], v});
            }
        }
    }
    int cur = e;
    while(cur != s) {
        nxt[prenode[cur].next] = {cur, prenode[cur].w};
        cur = prenode[cur].next;
    }

    while(cur != e) {
        cout << "cur: " << cur << endl;
        cur = nxt[cur].next;
    }
    cout << "cur: " << cur << endl;

    return;
}

/*
4 4 22 0 3                     
1 1  1 1
5 7 9 12
0 1 10
0 2 10
1 3 10
2 3 10

21
*/


// 走到s点,还剩余时间t
int maxval = -1;
void dfs(int s, int t, int val, int pre) {
    cout << "dfs: " <<  s << " " << t << " " << val << endl;
    if(t < 0) return;
    // 该点不玩
    if(s == e) {
        if(t >= times[s]) val += vals[s];
        if(val > maxval) maxval = val;
        return;
    }

    int v = nxt[s].next, w = nxt[s].w;
    dfs(v, t-w, val, pre);


    // 该点完
    if(vals[s] < pre)  return;  // 大于前面的开心值才能玩
    t -= times[s];
    val += vals[s];
    dfs(v, t-w, val, vals[s]);
}



int main() {
    cin >> n >> m >> t >> s >> e;
    for(int i = 0; i < n; i++) {
        int tmp;
        cin >> tmp;
        times[i] = tmp;
    }
    for(int i = 0; i < n; i++) {
        int tmp;
        cin >> tmp;
        vals[i] = tmp;
    }
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        Edge e1 = {v, w};
        Edge e2 = {u, w};
        edges[u].push_back(e1);
        edges[v].push_back(e2);
    }
    dijsktra(n, s, e);
    dfs(s, t, 0, -1);
    cout << maxval << endl;
}

有一道类似题 D-景区路线规划 概率dp+dfs
我觉得正解应该是Dijsktra变形+dp记忆化,优先队列中的节点 \([dist, id, time]\),类似于Leetcode 787. K 站中转内最便宜的航班

补充:发现原题了 https://izhen.me/2019/11/10/dp_graph/

第二题

题意:求最长的子串,且其最大值与最小值之差在\([m1, m2]\)内,如果有多个,输出子串和最大的

方法:
首先想到双指针,写法才发现不行,例如\(3 1 5 2, m1=3, m2=4\),双指针看到 \(3 1\) 时会发现不行然后就舍弃了,但是其实 \(3 1 5 2\) 这个整体是满足的
类似的题是LC1438. 绝对差不超过限制的最长连续子数组,它相当于没有下界,左端点舍弃了就舍弃了,不会影响

然后,只能暴力骗分了...,只通过了20%

最后,枚举左端点\(i\),右端点\(j\)其实是可以二分得到的,因为\(j\)越大,最大值与最小值之差肯定也越大,具有单调性。
但是这是带上下界的二分,且需要预处理区间最大最小值,需要用RMQ算法,,不想写。
补充:发现了原题 https://izhen.me/2019/11/10/stl_balancetree/

posted @ 2021-12-28 12:39  Rogn  阅读(253)  评论(0编辑  收藏  举报