description
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
analysis
可以设\(f[i]\)表示彻底杀死\(i\)怪兽的最小值,则\(f[i]=min(k[i],s[i]+\sum_{j\in son}f[j])\)
但是这种转移可以成环,所以不能用\(DP\)做,而这种类似松弛操作可以用\(SPFA\)来做
由于初始不知道从哪个点开始更新会最优,初始所有点都入队
\(dis[i]\)表示最小花费,一开始也不知道物理攻击以后如何转化,先都赋值成\(k[i]\)
更新\(now\)即为枚举所有\(now\)的儿子,拿\(\sum_{j\in son}dis[j]\)来更新\(dis[now]\)
对于队首\(now\)的更新,它的变动可能影响到所有经平A后可以得到\(now\)的点
所以建反向边,若队首更新成功,把可以得到队首的点全部再入队
\(dis[1]\)即为答案。这个做法时间复杂度应该是很大的……
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define MAXN 200005
#define MAXM 1000005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=las[a];i;i=nex[i])
#define rep1(i,a) for (reg i=las1[a];i;i=nex1[i])
using namespace std;
ll las[MAXM],nex[MAXM],tov[MAXM];
ll las1[MAXM],nex1[MAXM],tov1[MAXM];
ll dis[MAXN],phy[MAXN];
ll n,tot,tot1;
bool bz[MAXN];
queue<ll>q;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline ll max(ll x,ll y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline void link(ll x,ll y){nex[++tot]=las[x],las[x]=tot,tov[tot]=y;}
inline void link1(ll x,ll y){nex1[++tot1]=las1[x],las1[x]=tot1,tov1[tot1]=y;}
int main()
{
freopen("knight.in","r",stdin);
freopen("knight.out","w",stdout);
n=read();
fo(i,1,n)
{
phy[i]=read(),dis[i]=read();ll tmp=read(),x;
while (tmp--)x=read(),link(i,x),link1(x,i);
}
fo(i,1,n)q.push(i);
while (!q.empty())
{
ll now=q.front(),tmp=0;
q.pop(),bz[now]=1;
rep(i,now)tmp+=dis[tov[i]];
if (phy[now]+tmp<dis[now])
{
dis[now]=phy[now]+tmp;
rep1(i,now)if (bz[tov1[i]])q.push(tov1[i]),bz[tov1[i]]=0;
}
}
printf("%lld\n",dis[1]);
return 0;
}