首先正着搜是错的。。因为搜索的顺序会影响结果。。
那么就把所有点按法术攻击的大小都加入小根堆,每次取出最小的,那么解决它就只需要用法术攻击了。因为肯定存在解决它的儿子用法术攻击的情况,而且需要的花费比解决它的法术攻击还大,那必然用一次法术攻击解决它,不过存在当它没有儿子时,就把法术攻击和普通攻击取个min就对了。
这样就相当于在一个DAG上跑dijkstra了,当它们的父亲度数也为 \(0\) 了就可以更新。
复杂度 \(O(n \log n)\)
#include <bits/stdc++.h> #define ll long long namespace IO { const int MAXSIZE = 1 << 20; char buf[MAXSIZE], *p1, *p2; #define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++) void read() {} template<typename T, typename ... T2> inline void read(T &x, T2 &... oth) { x = 0; T f = 1; char ch = gc(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); } x *= f; read(oth...); } } const int N = 2e5 + 7; const int M = 1e6 + 7; int head1[N], head2[N], cnt = 1, n, deg[N]; ll dis[N], a[N]; struct E { int v, ne; } e[M << 1]; void add(int u, int v, int *head) { e[++cnt].v = v; e[cnt].ne = head[u]; head[u] = cnt; } struct Node { int u; ll d; Node(int _u = 0, ll _d = 0): u(_u), d(_d) {} bool operator < (const Node &p) const { return d > p.d; } }; std::priority_queue<Node> que; bool done[N]; int main() { IO::read(n); for (int i = 1, x; i <= n; i++) { IO::read(a[i], dis[i], deg[i]); for (int j = 1; j <= deg[i]; j++) { int x; IO::read(x); add(i, x, head1); add(x, i, head2); } if (!deg[i]) dis[i] = std::min(dis[i], a[i]); que.push(Node(i, dis[i])); } while (!que.empty()) { Node p = que.top(); que.pop(); int u = p.u; if (u == 1) break; if (done[u]) continue; done[u] = 1; for (int i = head2[u]; i; i = e[i].ne) { int fa = e[i].v; deg[fa]--; if (!deg[fa] && !done[fa]) { ll temp = a[fa]; for (int j = head1[fa]; j; j = e[j].ne) temp += dis[e[j].v]; if (temp < dis[fa]) { dis[fa] = temp; que.push(Node(fa, dis[fa])); } } } } printf("%lld\n", dis[1]); return 0; }
来源:https://www.cnblogs.com/Mrzdtz220/p/12296260.html