骑士游戏

题目大意

我们定义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
",dis[1]);
71     return 0;
72 }
原文地址:https://www.cnblogs.com/yufenglin/p/10885407.html