华为社招机试,面得实验室的研究岗,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算法,,不想写。