题目大意:给定n个怪物,每个怪物可以用魔法直接干掉,或者用物理攻击使其分裂为一些其他怪物,求杀掉1号怪物的最小花销
题解:f[i]表示杀死i号怪物的最小花销,则f[i]=min(k[i],s[i]+Σf[j])其中j为i用物理攻击后可以分裂为的怪物
但是直接DP有后效性,因此我们用SPFA来跑这个DP即可
每更新一个点A的动规值,就会有若干个点的动规值可能被更新,即可以分裂出点A的那些点。于是A出队后一旦动规值被更新了,就把那些点入队。
初始时要把所有点入队
我不知道这个怎么保证复杂度,十分玄学
我的收获:spfa处理有后效性dp
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int M=200005;
bool vis[M];
int n,t,R,x,head[M];
long long f[M],s[M],k[M];
vector<int> pre[M];
queue<int> q;
struct edge{int to,nex;}e[M*5];
void add(int u,int v){e[t].to=v,e[t].nex=head[u],head[u]=t++;}
void spfa()
{
for(int i=1;i<=n;i++) q.push(i),vis[i]=1,f[i]=k[i];
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
long long sum=s[u];
for(int i=head[u];i!=-1;i=e[i].nex) sum+=f[e[i].to];
if(sum>=f[u]) continue;
f[u]=sum;for(int i=0;i<pre[u].size();i++) if(!vis[pre[u][i]]) q.push(pre[u][i]),vis[pre[u][i]]=1;
}
}
void work()
{
spfa();
printf("%lld\n",f[1]);
}
void init()
{
cin>>n;memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++){
scanf("%lld%lld%d",&s[i],&k[i],&R);
for(int j=1;j<=R;j++) scanf("%d",&x),add(i,x),pre[x].push_back(i);
}
}
int main()
{
init();
work();
return 0;
}