这题目有点神,说一下思路
这个题目的怪物普通攻击砍死之后会分裂成其他怪兽,那么这个时候我们可以连一条边
并且正反向都连,方便后面转移
我们的初始值为彻底消灭的代价,那么我们很容易看出转移
k为彻底消灭代价,s为打分裂代价
k
[
n
o
w
]
=
m
i
n
(
k
[
n
o
w
]
,
s
[
n
o
w
s
o
n
]
+
∑
t
o
i
d
[
t
o
i
]
)
k[now]=min(k[now],s[now_{son}]+\sum_{to_i}d[to_i])
k[now]=min(k[now],s[nowson]+toi∑d[toi])
然后我们冷静思考一下来一根
我们做的这一件事会对哪些东西产生影响,会对那些会分裂成now的怪物有影响
那么我们反向建边的作用就出来了,这样就可以通过这题了
坑点大概只有俩吧
1.记得开long long
2.初始要把所有怪兽都入队,因为你不知道从哪个怪兽开始打是最优的,但是d是全局更新的,不用怕出锅,所以干脆全入队
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 2e5+7;
typedef long long ll;
ll n,d[maxn],k[maxn];
struct node{int to,next;}edge[maxn*10],edgefa[maxn*10];
int cnt,head[maxn],vis[maxn],headfa[maxn];
void add(int from,int to)
{
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
edgefa[cnt].to=from;
edgefa[cnt].next=headfa[to];
headfa[to]=cnt;
}
void spfa()
{
queue<int>q;
for(int i=1;i<=n;i++)q.push(i),vis[i]=1;
while(!q.empty())
{
int now=q.front();q.pop();vis[now]=0;
ll att=k[now];
for(int i=head[now];i;i=edge[i].next)att+=d[edge[i].to];
if(d[now]>att)
{
d[now]=att;
for(int i=headfa[now];i;i=edgefa[i].next)
if(!vis[edgefa[i].to])q.push(edgefa[i].to),vis[edgefa[i].to]=1;
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int r;
cin>>k[i]>>d[i]>>r;
while(r--)
{
int x;
cin>>x;
add(i,x);
}
}
spfa();
cout<<d[1];
}