1. 程式人生 > >BZOJ3875-[Ahoi2014&Jsoi2014]騎士遊戲

BZOJ3875-[Ahoi2014&Jsoi2014]騎士遊戲


題解:
我們可以令f[i]表示殺死i怪獸的最小代價。
f[i]=min(k[i],s[i]+(f[j]))ji受到物理攻擊後分裂成的所有怪獸。
我們發現直接dp是有後效性的,我們可以用SPFA來做這個dp
用兩個陣列每次更新差值就好了。
Code

#include<bits/stdc++.h>
#define ll long long
#define N 300005
using namespace std;
struct edge
{
    int vet,next;
}edge[N<<2
]; int head[N],tot=0; void add_edge(int u,int v) { edge[++tot].vet=v; edge[tot].next=head[u]; head[u]=tot; } vector<int>vet[N]; ll f[N],s[N],vis[N]; int n,r; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld%lld",&s[i],&f[i]); int
w; scanf("%d",&w); for(int j=1;j<=w;j++) { int r; scanf("%d",&r); add_edge(i,r); vet[r].push_back(i); } } queue<int>Q; for(int i=1;i<=n;i++) { Q.push(i); vis[i]=1; } while
(!Q.empty()) { int u=Q.front(); Q.pop(); vis[u]=0; ll tmp=s[u]; for(int i=head[u];i;i=edge[i].next) tmp+=f[edge[i].vet]; if(tmp>=f[u])continue; f[u]=tmp; for(int i=0;i<vet[u].size();i++) if(!vis[vet[u][i]]) { vis[vet[u][i]]=1; Q.push(vet[u][i]); } } printf("%lld\n",f[1]); return 0; }