题解:
我们可以令
f[i]
f
[
i
]
表示杀死i怪兽的最小代价。
f[i]=min(k[i],s[i]+∑(f[j]))
f
[
i
]
=
m
i
n
(
k
[
i
]
,
s
[
i
]
+
∑
(
f
[
j
]
)
)
,
j
j
为受到物理攻击后分裂成的所有怪兽。
我们发现直接
dp
d
p
是有后效性的,我们可以用
SPFA
S
P
F
A
来做这个
dp
d
p
。
用两个数组每次更新差值就好了。
Code:
C
o
d
e
:
#include<bits/stdc++.h>
#define ll long long
#define N 300005
using namespace std;
struct edge
{
int vet,next;
}edge[N<<2];
int head[N],tot=0;
void add_edge(int u,int v)
{
edge[++tot].vet=v;
edge[tot].next=head[u];
head[u]=tot;
}
vector<int>vet[N];
ll f[N],s[N],vis[N];
int n,r;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&s[i],&f[i]);
int w;
scanf("%d",&w);
for(int j=1;j<=w;j++)
{
int r;
scanf("%d",&r);
add_edge(i,r);
vet[r].push_back(i);
}
}
queue<int>Q;
for(int i=1;i<=n;i++)
{
Q.push(i);
vis[i]=1;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]=0;
ll tmp=s[u];
for(int i=head[u];i;i=edge[i].next)
tmp+=f[edge[i].vet];
if(tmp>=f[u])continue;
f[u]=tmp;
for(int i=0;i<vet[u].size();i++)
if(!vis[vet[u][i]])
{
vis[vet[u][i]]=1;
Q.push(vet[u][i]);
}
}
printf("%lld\n",f[1]);
return 0;
}