「AHOI2014/JSOI2014」骑士游戏

「AHOI2014/JSOI2014」骑士游戏

传送门
考虑 ( ext{DP})
(dp_i) 表示灭种(雾)一只编号为 (i) 的怪物的代价。
那么转移显然是:

[dp_i = min(K_i, S_i + sum_{j = 1}^{R_i} dp_{v_j}) ]

但是我们会发现这个东西是有后效性的。。。
所以我们会想要用建图然后跑一个最短路什么的来搞。。。
于是我们观察到上面那个 ( ext{DP}) 式子中,(dp_i) 如果用后面那一项来转移,显然会有 (dp_{v_j} < dp_i)
这提示我们,为了消除后效性,可以对 (dp) 值排序。
准确的说就是开一个堆来搞,每个点初始的 (dp) 值都是消灭它的魔法消耗,然后优先更新较小的 (dp) 值,
毕竟我们对于魔法消耗最小的怪物肯定是直接消灭(因为你到头来都要干死它何必生出一些魔法消耗更高的嘞)
然后我们建图方式就是反着来,如果 (i) 会生出 (j),那么连边 (j o i),然后我们就跑一个长的有点像 ( ext{Dijkstra})( ext{DP}) 就好了。
参考代码:

#include <cstdio>
#include <queue>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

typedef long long LL;
const int _ = 2e5 + 5, __ = 1e6 + 5;

int tot, head[_]; struct Edge { int ver, nxt; } edge[__];
inline void Add_edge(int u, int v) { edge[++tot] = (Edge) { v, head[u] }, head[u] = tot; }

int n, r[_], vis[_]; LL dp[_], s[_], k[_];
struct node { int u; LL val; } ;
inline bool operator < (const node& x, const node& y) { return x.val > y.val; }

priority_queue < node > Q;

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n);
    for (rg int i = 1; i <= n; ++i) {
	    read(s[i]), read(k[i]), read(r[i]);
	    for (rg int x, o = 1; o <= r[i]; ++o) read(x), Add_edge(x, i);
    }
    for (rg int i = 1; i <= n; ++i) Q.push((node) { i, dp[i] = k[i] });
    while (!Q.empty()) {
	    int u = Q.top().u; Q.pop();
	    if (vis[u]) continue ; vis[u] = 1;
	    for (rg int i = head[u]; i; i = edge[i].nxt) {
    	    int v = edge[i].ver;
	        s[v] += dp[u];
	        if (dp[v] > s[v] && !--r[v])
		        dp[v] = s[v], Q.push((node) { v, dp[v] });
	    }
    }
    printf("%lld
", dp[1]);
    return 0;
}
原文地址:https://www.cnblogs.com/zsbzsb/p/12254210.html