思路
刚做了前两天的题,所以第一想法还是BFS。MLE了,而且感觉同时也TLE了。其实仔细想想会发现,BFS是要遍历所有路径才能找到最终答案的,所以会超时也不奇怪了。
题目要求 最大最小边成本 成本,常见的可以想到二分,而且确实是满足单调性条件的(如果最大分数mid能满足,那么所有<=mid的最大分数都能满足)。
那么解题方法就清晰了,二分可能的最大分数值,每次DFS(因为要求有解而非遍历,所以DFS比BFS一般效率更高)查看是否能够满足。
这次速度快多了,但是卡最后几个案例上,那么就考虑剪枝和记忆化。其实之前是有考虑 TotalCost>k的剪枝,但是依然超时了,这次就新增记忆化搜索,记忆DFS到p点时到终点的总消耗(跟之前剪枝有冲突,就去掉了),终于过了 ^-^
代码
class Solution {
private long k;
private int n;
private List<int[]>[] path;
private long[] remainCost;
public int findMaxPathScore(int[][] edges, boolean[] online, long k) {
this.k = k;
n = online.length;
remainCost = new long[n];
path = new ArrayList[n];
int l = Integer.MAX_VALUE, r = 0;
for (int i = 0; i < n; i++) {
path[i] = new ArrayList<>();
}
for (int[] edge : edges) {
if (online[edge[0]] && online[edge[1]]) {
int cost = edge[2];
l = Math.min(l, cost);
r = Math.max(r, cost);
path[edge[0]].add(new int[]{edge[1], cost});
}
}
Arrays.fill(remainCost, -1);
if (dfs(0, 0) > k) {
return -1;
}
int ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
Arrays.fill(remainCost, -1);
if (dfs(mid, 0) <= k) {
ans = Math.max(ans, mid);
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
private long dfs(int mid, int p) {
if (p == n - 1) {
return 0;
}
if (remainCost[p] >= 0) {
return remainCost[p];
}
long minRemain = k + 1;
for (int[] next : path[p]) {
long cost = next[1];
if (cost < mid) {
continue;
}
minRemain = Math.min(minRemain, dfs(mid, next[0]) + cost);
}
remainCost[p] = minRemain;
return minRemain;
}
}