题目大意:给定n个怪物,每个怪物可以用魔法直接干掉,或者用物理攻击使其分裂为一些其他怪物,求杀掉1号怪物的最小花销
令f[i]为杀死i号怪物的最小花销,则f[i]=min(k[i],s[i]+Σf[j]) 其中j为i用物理攻击后可以分裂为的怪物
但是直接DP有后效性,因此我们用SPFA来跑这个DP即可
注意如果每次更新一个点之后都重新计算花销会T掉
改成减掉花销的差值就好了 具体写法去看代码吧- -
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct abcd{
int to,next;
}table[2002002];
int head1[M],head2[M],tot;
int n,m;
long long f[M],g[M],phisical_attack[M],magic_attack[M];
//f[x]代表最小花销
//g[x]代表用物理攻击的最小花销
int q[M],r,h;
bool v[M];
void Add(int head[],int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void SPFA()
{
int i;
while(r!=h)
{
int x=q[(++h)%=M];v[x]=0;
if(g[x]>=f[x])
continue;
for(i=head2[x];i;i=table[i].next)
{
if(!v[table[i].to])
v[table[i].to]=true,q[(++r)%=M]=table[i].to;
g[table[i].to]-=f[x];
g[table[i].to]+=g[x];
}
f[x]=g[x];
}
}
int main()
{
int i,j,x;
cin>>n;
for(i=1;i<=n;i++)
{
#ifdef ONLINE_JUDGE
scanf("%lld%lld",&phisical_attack[i],&magic_attack[i]);
#else
scanf("%I64d%I64d",&phisical_attack[i],&magic_attack[i]);
#endif
q[++r]=i;v[i]=true;
scanf("%d",&m);
for(j=1;j<=m;j++)
{
scanf("%d",&x);
Add(head1,i,x);
Add(head2,x,i);
}
}
for(i=1;i<=n;i++)
{
f[i]=magic_attack[i];
g[i]=phisical_attack[i];
for(j=head1[i];j;j=table[j].next)
g[i]+=magic_attack[table[j].to];
}
SPFA();
cout<<f[1]<<endl;
return 0;
}