1. 程式人生 > 實用技巧 >什麼是腦裂?

什麼是腦裂?

題意

有\(n\)個怪物,可以消耗\(k\)的代價消滅一個怪物或者消耗\(s\)的代價將它變成另外一個或多個新的怪物,求消滅怪物$的最小代價

思路

\(DP\)+最短路

這幾天做的第一道自己能\(yy\)出來的題……

看起來像是個\(\texttt{DP}\),認真思考一會兒也不難想到可以設計如下狀態

設\(f[i]\)為消滅\(i\)所需的最小代價,那麼有

\[f[i]=\min(f[i], s[i]+\sum\limits_{to_i} f[to_i])
\]

其中\(to\)表示\(i\)點的後繼

因為\(f\)的轉移之間相互干涉,所以用最短路處理

先建雙向邊,方便之後轉移,然後用\(\texttt{SPFA}\)(它死了求"多源"最短路就好了

因為不知道一開始應該打哪個怪物,所以乾脆全都入隊、全部更新就好了

\(ps:\)兩年\(\text{OI}\)一場空,不開\(long\ long\)見祖宗

程式碼

/*
Author:Loceaner
*/
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std; const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f; inline int read() {
char c = getchar(); int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
} queue <int> Q;
vector <int> v1[A], v2[A];
int n, m, ord[A], mag[A]/*題目中所給的s[i],k[i]*/, vis[A]; inline void ZDL() {
for (int i = 1; i <= n; i++) Q.push(i), vis[i] = 1;
while (!Q.empty()) {
int x = Q.front(); Q.pop(), vis[x] = 0;
int res = ord[x];
for (int i = 0; i < (int)v1[x].size(); i++) res += mag[v1[x][i]];
if (res < mag[x]) {
mag[x] = res;
for (int i = 0; i < (int)v2[x].size(); i++)
if (!vis[v2[x][i]]) Q.push(v2[x][i]), vis[v2[x][i]] = 1;
}
}
} signed main() {
n = read();
for (int i = 1, k; i <= n; i++) {
ord[i] = read(), mag[i] = read(), k = read();
while (k--) {
int x = read();
v1[i].push_back(x), v2[x].push_back(i);
}
}
ZDL();
cout << mag[1] << '\n';
return 0;
}