description
在這個遊戲中,JYY一共有兩種攻擊方式,一種是普通攻擊,一種是法術攻擊。兩種攻擊方式都會消耗JYY一些體力。採用普通攻擊進攻怪獸並不能把怪獸徹底殺死,怪獸的屍體可以變出其他一些新的怪獸,注意一個怪獸可能經過若干次普通攻擊後變回一個或更多同樣的怪獸;而採用法術攻擊則可以徹底將一個怪獸殺死。當然了,一般來說,相比普通攻擊,法術攻擊會消耗更多的體力值(但由於遊戲系統bug,並不保證這一點)。
遊戲世界中一共有N種不同的怪獸,分別由1到N編號,現在1號怪獸入侵村莊了,JYY想知道,最少花費多少體力值才能將所有村莊中的怪獸全部殺死呢?
analysis
-
可以設表示徹底殺死怪獸的最小值,則
-
但是這種轉移可以成環,所以不能用做,而這種類似鬆弛操作可以用來做
-
由於初始不知道從哪個點開始更新會最優,初始所有點都入隊
-
表示最小花費,一開始也不知道物理攻擊以後如何轉化,先都賦值成
-
更新即爲枚舉所有的兒子,拿來更新
-
對於隊首的更新,它的變動可能影響到所有經平A後可以得到的點
-
所以建反向邊,若隊首更新成功,把可以得到隊首的點全部再入隊
-
即爲答案。這個做法時間複雜度應該是很大的……
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;
}