comments | difficulty | edit_url | tags | |||
---|---|---|---|---|---|---|
true |
困难 |
|
Bob 被困在了一个地窖里,他需要破解 n
个锁才能逃出地窖,每一个锁都需要一定的 能量 才能打开。每一个锁需要的能量存放在一个数组 strength
里,其中 strength[i]
表示打开第 i
个锁需要的能量。
Bob 有一把剑,它具备以下的特征:
- 一开始剑的能量为 0 。
- 剑的能量增加因子
X
一开始的值为 1 。 - 每分钟,剑的能量都会增加当前的
X
值。 - 打开第
i
把锁,剑的能量需要到达 至少strength[i]
。 - 打开一把锁以后,剑的能量会变回 0 ,
X
的值会增加 1。
你的任务是打开所有 n
把锁并逃出地窖,请你求出需要的 最少 分钟数。
请你返回 Bob 打开所有 n
把锁需要的 最少 时间。
示例 1:
输入:strength = [3,4,1]
输出:4
解释:
时间 | 能量 | X | 操作 | 更新后的 X |
---|---|---|---|---|
0 | 0 | 1 | 什么也不做 | 1 |
1 | 1 | 1 | 打开第 3 把锁 | 2 |
2 | 2 | 2 | 什么也不做 | 2 |
3 | 4 | 2 | 打开第 2 把锁 | 3 |
4 | 3 | 3 | 打开第 1 把锁 | 3 |
无法用少于 4 分钟打开所有的锁,所以答案为 4 。
示例 2:
输入:strength = [2,5,4]
输出:6
解释:
时间 | 能量 | X | 操作 | 更新后的 X |
---|---|---|---|---|
0 | 0 | 1 | 什么也不做 | 1 |
1 | 1 | 1 | 什么也不做 | 1 |
2 | 2 | 1 | 打开第 1 把锁 | 2 |
3 | 2 | 2 | 什么也不做 | 2 |
4 | 4 | 2 | 打开第 3 把锁 | 3 |
5 | 3 | 3 | 什么也不做 | 3 |
6 | 6 | 3 | 打开第 2 把锁 | 4 |
无法用少于 6 分钟打开所有的锁,所以答案为 6。
提示:
n == strength.length
1 <= n <= 80
1 <= strength[i] <= 106
n == strength.length
class MCFGraph:
class Edge(NamedTuple):
src: int
dst: int
cap: int
flow: int
cost: int
class _Edge:
def __init__(self, dst: int, cap: int, cost: int) -> None:
self.dst = dst
self.cap = cap
self.cost = cost
self.rev: Optional[MCFGraph._Edge] = None
def __init__(self, n: int) -> None:
self._n = n
self._g: List[List[MCFGraph._Edge]] = [[] for _ in range(n)]
self._edges: List[MCFGraph._Edge] = []
def add_edge(self, src: int, dst: int, cap: int, cost: int) -> int:
assert 0 <= src < self._n
assert 0 <= dst < self._n
assert 0 <= cap
m = len(self._edges)
e = MCFGraph._Edge(dst, cap, cost)
re = MCFGraph._Edge(src, 0, -cost)
e.rev = re
re.rev = e
self._g[src].append(e)
self._g[dst].append(re)
self._edges.append(e)
return m
def get_edge(self, i: int) -> Edge:
assert 0 <= i < len(self._edges)
e = self._edges[i]
re = cast(MCFGraph._Edge, e.rev)
return MCFGraph.Edge(re.dst, e.dst, e.cap + re.cap, re.cap, e.cost)
def edges(self) -> List[Edge]:
return [self.get_edge(i) for i in range(len(self._edges))]
def flow(self, s: int, t: int, flow_limit: Optional[int] = None) -> Tuple[int, int]:
return self.slope(s, t, flow_limit)[-1]
def slope(
self, s: int, t: int, flow_limit: Optional[int] = None
) -> List[Tuple[int, int]]:
assert 0 <= s < self._n
assert 0 <= t < self._n
assert s != t
if flow_limit is None:
flow_limit = cast(int, sum(e.cap for e in self._g[s]))
dual = [0] * self._n
prev: List[Optional[Tuple[int, MCFGraph._Edge]]] = [None] * self._n
def refine_dual() -> bool:
pq = [(0, s)]
visited = [False] * self._n
dist: List[Optional[int]] = [None] * self._n
dist[s] = 0
while pq:
dist_v, v = heappop(pq)
if visited[v]:
continue
visited[v] = True
if v == t:
break
dual_v = dual[v]
for e in self._g[v]:
w = e.dst
if visited[w] or e.cap == 0:
continue
reduced_cost = e.cost - dual[w] + dual_v
new_dist = dist_v + reduced_cost
dist_w = dist[w]
if dist_w is None or new_dist < dist_w:
dist[w] = new_dist
prev[w] = v, e
heappush(pq, (new_dist, w))
else:
return False
dist_t = dist[t]
for v in range(self._n):
if visited[v]:
dual[v] -= cast(int, dist_t) - cast(int, dist[v])
return True
flow = 0
cost = 0
prev_cost_per_flow: Optional[int] = None
result = [(flow, cost)]
while flow < flow_limit:
if not refine_dual():
break
f = flow_limit - flow
v = t
while prev[v] is not None:
u, e = cast(Tuple[int, MCFGraph._Edge], prev[v])
f = min(f, e.cap)
v = u
v = t
while prev[v] is not None:
u, e = cast(Tuple[int, MCFGraph._Edge], prev[v])
e.cap -= f
assert e.rev is not None
e.rev.cap += f
v = u
c = -dual[s]
flow += f
cost += f * c
if c == prev_cost_per_flow:
result.pop()
result.append((flow, cost))
prev_cost_per_flow = c
return result
class Solution:
def findMinimumTime(self, a: List[int]) -> int:
n = len(a)
s = n * 2
t = s + 1
g = MCFGraph(t + 1)
for i in range(n):
g.add_edge(s, i, 1, 0)
g.add_edge(i + n, t, 1, 0)
for j in range(n):
g.add_edge(i, j + n, 1, (a[i] - 1) // (j + 1) + 1)
return g.flow(s, t, n)[1]
class MCFGraph {
static class Edge {
int src, dst, cap, flow, cost;
Edge(int src, int dst, int cap, int flow, int cost) {
this.src = src;
this.dst = dst;
this.cap = cap;
this.flow = flow;
this.cost = cost;
}
}
static class _Edge {
int dst, cap, cost;
_Edge rev;
_Edge(int dst, int cap, int cost) {
this.dst = dst;
this.cap = cap;
this.cost = cost;
this.rev = null;
}
}
private int n;
private List<List<_Edge>> graph;
private List<_Edge> edges;
public MCFGraph(int n) {
this.n = n;
this.graph = new ArrayList<>();
this.edges = new ArrayList<>();
for (int i = 0; i < n; i++) {
graph.add(new ArrayList<>());
}
}
public int addEdge(int src, int dst, int cap, int cost) {
assert (0 <= src && src < n);
assert (0 <= dst && dst < n);
assert (0 <= cap);
int m = edges.size();
_Edge e = new _Edge(dst, cap, cost);
_Edge re = new _Edge(src, 0, -cost);
e.rev = re;
re.rev = e;
graph.get(src).add(e);
graph.get(dst).add(re);
edges.add(e);
return m;
}
public Edge getEdge(int i) {
assert (0 <= i && i < edges.size());
_Edge e = edges.get(i);
_Edge re = e.rev;
return new Edge(re.dst, e.dst, e.cap + re.cap, re.cap, e.cost);
}
public List<Edge> edges() {
List<Edge> result = new ArrayList<>();
for (int i = 0; i < edges.size(); i++) {
result.add(getEdge(i));
}
return result;
}
public int[] flow(int s, int t, Integer flowLimit) {
List<int[]> result = slope(s, t, flowLimit);
return result.get(result.size() - 1);
}
public List<int[]> slope(int s, int t, Integer flowLimit) {
assert (0 <= s && s < n);
assert (0 <= t && t < n);
assert (s != t);
if (flowLimit == null) {
flowLimit = graph.get(s).stream().mapToInt(e -> e.cap).sum();
}
int[] dual = new int[n];
Tuple[] prev = new Tuple[n];
List<int[]> result = new ArrayList<>();
result.add(new int[] {0, 0});
while (true) {
if (!refineDual(s, t, dual, prev)) {
break;
}
int f = flowLimit;
int v = t;
while (prev[v] != null) {
Tuple tuple = prev[v];
int u = tuple.first;
_Edge e = tuple.second;
f = Math.min(f, e.cap);
v = u;
}
v = t;
while (prev[v] != null) {
Tuple tuple = prev[v];
int u = tuple.first;
_Edge e = tuple.second;
e.cap -= f;
e.rev.cap += f;
v = u;
}
int c = -dual[s];
result.add(new int[] {
result.get(result.size() - 1)[0] + f, result.get(result.size() - 1)[1] + f * c});
if (c == result.get(result.size() - 2)[1]) {
result.remove(result.size() - 2);
}
}
return result;
}
private boolean refineDual(int s, int t, int[] dual, Tuple[] prev) {
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
pq.add(new int[] {0, s});
boolean[] visited = new boolean[n];
Integer[] dist = new Integer[n];
Arrays.fill(dist, null);
dist[s] = 0;
while (!pq.isEmpty()) {
int[] current = pq.poll();
int distV = current[0];
int v = current[1];
if (visited[v]) continue;
visited[v] = true;
if (v == t) break;
int dualV = dual[v];
for (_Edge e : graph.get(v)) {
int w = e.dst;
if (visited[w] || e.cap == 0) continue;
int reducedCost = e.cost - dual[w] + dualV;
int newDist = distV + reducedCost;
Integer distW = dist[w];
if (distW == null || newDist < distW) {
dist[w] = newDist;
prev[w] = new Tuple(v, e);
pq.add(new int[] {newDist, w});
}
}
}
if (!visited[t]) return false;
int distT = dist[t];
for (int v = 0; v < n; v++) {
if (visited[v]) {
dual[v] -= distT - dist[v];
}
}
return true;
}
static class Tuple {
int first;
_Edge second;
Tuple(int first, _Edge second) {
this.first = first;
this.second = second;
}
}
}
class Solution {
public int findMinimumTime(int[] strength) {
int n = strength.length;
int s = n * 2;
int t = s + 1;
MCFGraph g = new MCFGraph(t + 1);
for (int i = 0; i < n; i++) {
g.addEdge(s, i, 1, 0);
g.addEdge(i + n, t, 1, 0);
for (int j = 0; j < n; j++) {
g.addEdge(i, j + n, 1, (strength[i] - 1) / (j + 1) + 1);
}
}
return g.flow(s, t, n)[1];
}
}