bzoj3875: [Ahoi2014&Jsoi2014]骑士游戏(spfa+dp)

183 篇文章 0 订阅
63 篇文章 1 订阅

传送门
题意简述: n n n个怪物,对于编号为 i i i的怪物可以选择用 a i a_i ai代价将其分裂成另外的 b i b_i bi个怪物或者用 c i c_i ci代价直接消灭它,现在问消灭编号为1的怪物用的最小代价。


思路:考虑 d p dp dp,消灭 i i i号怪物的代价 f i = m i n { c i , a i ∑ f v } , v 指 分 裂 的 怪 物 f_i=min\{c_i,a_i\sum f_v\},v指分裂的怪物 fi=min{ci,aifv},v
然后这个东西可能有后效性,考虑如何处理后效在这里插入代码片性。
发现可以用分裂关系来建立有向图来 d p dp dp,每个怪物的代价相当于只跟后继的代价有关,这样可以用 s p f a spfa spfa来维护 d p dp dp,由于一旦一个怪物被更新会影响到所有能分裂出它的怪物,因此我们同时建立一个反图,一旦一个怪物被更新就把反图的后继加进队列。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
const int N=2e5+5;
ll dist[N],s[N];
int q[N*20],hd,tl,n;
bool in[N];
vector<int>e[N],g[N];
inline void spfa(){
    hd=1,tl=0;
    for(ri i=1;i<=n;++i)in[q[++tl]=i]=1;
    while(hd<=tl){
        int x=q[hd++];
        in[x]=0;
        ll tmp=s[x];
        for(ri i=0;i<e[x].size();++i)tmp+=dist[e[x][i]];
        if(tmp>=dist[x])continue;
        dist[x]=tmp;
        for(ri i=0;i<g[x].size();++i)if(!in[g[x][i]])in[q[++tl]=g[x][i]]=1;
    }
}
int main(){
    n=read();
    for(ri i=1,k,v;i<=n;++i){
        s[i]=read(),dist[i]=read();
        k=read();
        while(k--)v=read(),e[i].push_back(v),g[v].push_back(i);
    }
    spfa();
    cout<<dist[1];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值