我们定义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 EDGE 14 { 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<int>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<dis[s]) 47 { 48 dis[s]=res; 49 for(reg int i=fir[s];i;i=rev[i].nxt) if(vis[rev[i].to]==0) q.push(rev[i].to),vis[rev[i].to]=1; 50 } 51 } 52 } 53 int main() 54 { 55 scanf("%d",&n); 56 UF(i,1,n) 57 { 58 c[i] = read(),dis[i] = read(); 59 int z; 60 scanf("%d",&z); 61 UF(j,1,z) 62 { 63 int k; 64 scanf("%d",&k); 65 add(i,k); 66 addrev(k,i); 67 } 68 } 69 SPFA(); 70 printf("%lld\n",dis[1]); 71 return 0; 72 }
原文地址:https://www.cnblogs.com/yufenglin/p/10885407.html
时间: 2024-10-12 02:36:13