我们定义dis[i]代表完全杀死i号怪兽的最小体力值花费,那么初始值都是法术攻击的花费。
那么动态转移方程就是:dis[i]=min(magic[i],common[i]+∑son:(dis[i]))
但是我们会发现直接搞dp的话是有后效性的,比如:1-->2-->1那么就会陷入死循环
但是我们惊奇的发现这个好像和SPFA的松弛操作有一些相像,所以我们改变思路,跑一遍SPFA
由于从起点开始跑等于直接比较儿子节点的魔法费用,显然是错误的,所以将所有点全部压入队列中进行考虑
并且如果一个节点的儿子节点被考虑过之后,父节点也会受影响,所以也要重新决策一次
时间复杂度可以看作是SPFA的复杂度上加一个小常数,具体不会证,注意常数优化
最后,附上本题代码:(自动省略头文件)
1 il LL read() 2 { 3 reg LL w=0; 4 char ch=getchar(); 5 while(ch<'0'||ch>'9') ch=getchar(); 6 while(ch>='0'&&ch<='9') 7 { 8 w=(w<<3)+(w<<1)+ch-'0'; 9 ch=getchar();10 }11 return w;12 }13 struct EDGE14 {15 int to,nxt;16 };17 EDGE edge[maxm+5],rev[maxm + 5];18 int n,cnt;19 LL dis[maxn+5],c[maxn+5];20 int head[maxn+5];21 bool vis[maxn+5];22 queue q;23 24 il void add(int x,int y)25 {26 edge[++cnt].to=y;27 edge[cnt].nxt=head[x];28 head[x]=cnt;29 }30 int fir[maxn + 5],alloc;31 il void addrev(int u,int v)32 {33 rev[++alloc].nxt = fir[u];34 fir[u] = alloc;35 rev[alloc].to = v;36 }37 il void SPFA()38 {39 UF(i,1,n) q.push(i),vis[i]=1;40 while(!q.empty())41 {42 reg int s=q.front();43 reg LL res=c[s];44 vis[s]=0,q.pop();45 for(reg int i=head[s]; i; i=edge[i].nxt) res+=dis[edge[i].to];46 if(res