【BZOJ3875】【Ahoi2014】骑士游戏 SPFA处理有后效性动规

广告:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44040735");
}

题解:

首先一个点可以分裂成多个新点,这样就有了图上动规的基础。

即f[i]表示i点被消灭的最小代价,它可以由分裂出的点们更新。

但是这个东西有后效性,所以我们用SPFA来处理它。

spfa处理后效性动规

我们每更新一个点A的动规值,就会有若干个点的动规值可能被更新。

即可以分裂出点A的那些点。

于是A出队后一旦动规值被更新了,就把那些点入队。

初始时要把所有点入队,因为它们都可能被更新。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 201000
#define M 2010000
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
    int v,next;
}e[M],E[M];
int head[N],HEAD[N],cnt;
inline void add(int u,int v)
{
    e[++cnt].v=v;
    E[cnt].v=u;
    e[cnt].next=head[u];
    E[cnt].next=HEAD[v];
    HEAD[v]=head[u]=cnt;

}
long long A[N],dist[N];
bool in[N];
int n;
queue<int>q;
void spfa()
{
    while(!q.empty())q.pop();

    int i,u,v;
    for(i=1;i<=n;i++)q.push(i),in[i]=1;
    while(!q.empty())
    {
        u=q.front(),q.pop(),in[u]=0;
        long long temp=A[u];
        for(i=head[u];i;i=e[i].next)
            temp+=dist[e[i].v];
        if(temp>=dist[u])continue;
        dist[u]=temp;
        for(i=HEAD[u];i;i=E[i].next)
            if(!in[v=E[i].v])q.push(v),in[v]=1;
    }
}
int main()
{
    int i,j,k;
    int a,b,c;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        cin>>A[i]>>dist[i]>>c;
        while(c--)
        {
            scanf("%d",&a);
            add(i,a);
        }
    }
    spfa();
    cout<<dist[1];
    return 0;
}
时间: 2024-08-03 15:04:09

【BZOJ3875】【Ahoi2014】骑士游戏 SPFA处理有后效性动规的相关文章

bzoj3875 [Ahoi2014]骑士游戏

Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽:而采用法术攻击则可以彻底将一个怪兽杀死.当然了,一般来说,相比普通攻击,

BZOJ 3875 Ahoi2014 骑士游戏 SPFA

题目大意:给定n个怪物,每个怪物可以用魔法直接干掉,或者用物理攻击使其分裂为一些其他怪物,求杀掉1号怪物的最小花销 令f[i]为杀死i号怪物的最小花销,则f[i]=min(k[i],s[i]+Σf[j]) 其中j为i用物理攻击后可以分裂为的怪物 但是直接DP有后效性,因此我们用SPFA来跑这个DP即可 注意如果每次更新一个点之后都重新计算花销会T掉 改成减掉花销的差值就好了 具体写法去看代码吧- - #include <cstdio> #include <cstring> #inc

[BZOJ3875][AHOI2014]骑士游戏(松弛操作)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3875 分析: 类似于spfa求最短路,设d[i]表示完全消灭i号怪物的最小花费,我们对d[]进行动态更新 我们可以把问题反向:一开始所有怪物都存活,我们要找到一个怪物合成方案合成1号怪物,其中合成方法有两种,一种是魔法攻击逆向产生怪物,另一种就是由某个怪物的后继怪物合成此怪物 对于第一种产生方法的表示,令初始的d[i]=k[i]即可 对于第二种产生方法的表示,也就是算法的核心——类似

BZOJ 3875 Ahoi2014 骑士游戏

3875: [Ahoi2014]骑士游戏 Time Limit: 30 Sec  Memory Limit: 256 MB Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会 扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个

【BZOJ3875】[Ahoi2014]骑士游戏【最短路】【DP】

[题目链接] 对于怪物u,普通攻击打死后产生的怪物为vi.设dis[u]表示打死u的最小花费,那么有 dis[u] = min{s[u] + ∑dis[vi], k[u]} 以这个为松弛条件,跑spfa就可以啦. 然而BZOJ跑了29s...变为倒数rank1 /* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> using namespace s

[AHOI2014/JSOI2014]骑士游戏(SPFA认识)

传送门 好题!考察了对于SPFA的深刻理解. 对于每个怪,我们要么花费魔攻代价,要么花费普攻代价+消灭其儿子的代价. 看似像个一直递归下去的做法,仿佛可以用dp? 但是图中可能会存在环,就会有后效性. 假如我们用一个队列保存当前还需要消灭的怪. 我们每次提出队首,要么魔攻,要么普攻然后又压入一堆新出现的怪.直到队为空. 感觉这个过程有点像SPFA. SPFA是对于每次那些还可能松弛更新的边进行松弛,直到无法操作(队空)就保证了最短路. 对于这道题,我们好像也可以每次看能不能再更新消灭怪的最小花费

「AHOI2014/JSOI2014」骑士游戏

「AHOI2014/JSOI2014」骑士游戏 传送门 考虑 \(\text{DP}\). 设 \(dp_i\) 表示灭种(雾)一只编号为 \(i\) 的怪物的代价. 那么转移显然是: \[dp_i = \min(K_i, S_i + \sum_{j = 1}^{R_i} dp_{v_j})\] 但是我们会发现这个东西是有后效性的... 所以我们会想要用建图然后跑一个最短路什么的来搞... 于是我们观察到上面那个 \(\text{DP}\) 式子中,\(dp_i\) 如果用后面那一项来转移,显然

骑士游戏

题目大意 我们定义dis[i]代表完全杀死i号怪兽的最小体力值花费,那么初始值都是法术攻击的花费. 那么动态转移方程就是:dis[i]=min(magic[i],common[i]+∑son:(dis[i])) 但是我们会发现直接搞dp的话是有后效性的,比如:1-->2-->1那么就会陷入死循环 但是我们惊奇的发现这个好像和SPFA的松弛操作有一些相像,所以我们改变思路,跑一遍SPFA 由于从起点开始跑等于直接比较儿子节点的魔法费用,显然是错误的,所以将所有点全部压入队列中进行考虑 并且如果一

Uva 11324 The Largest Clique【强连通 DAG动规 spfa】

白书上的例题 做一遍tarjan后,缩点,每一个scc节点的权为它的结点数,做一次DAG上的动规,求出路径上的最大点权和,就可以了 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const i