题目大意:给定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; }
时间: 2024-10-12 02:36:16