/* 返回顶部 */

Luogu P4042 [AHOI2014/JSOI2014]骑士游戏

前往>>暴风城

第一次写SPFA!(惭愧

对于某个怪兽,杀死它的最小消耗 = min(它的魔法消耗,它的物理消耗 + 杀死它所有儿子的消耗)

可以看出,一个点可能被它的儿子更新,并且可能去更新它的父亲。

考虑用最短路解决这道题,从一个假设的起点0出发,要求它到1的最短距离。1~n每个点的距离初始应为INF。

将每个怪物的消耗更新为它的魔法消耗,并加入队列;

弹出队首,检查它能不能被更新。如果可以,则说明它有可能更新它的父亲,将它的所有父亲加入队列;

直到队列为空为止。

代码如下

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define MogeKo qwq
#include<queue>
using namespace std;
const int maxn = 2e6;
int n,r,x;
long long ad[maxn],ap[maxn],dis[maxn];
int head[maxn][2],to[maxn][2],nxt[maxn][2],cnt[2];
bool vis[maxn];
queue <int> q;

void add(int x,int y,int op) {
    to[++cnt[op]][op] = y;
    nxt[cnt[op]][op] = head[x][op];
    head[x][op] = cnt[op];
}

void SPFA() {
    for(int i = 1; i <= n; i++) {
        q.push(i);
        vis[i] = true;
    }
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
        long long tem = ad[u];
        for(int i = head[u][1]; i; i = nxt[i][1])
            tem += dis[to[i][1]];
        if(tem >= dis[u])continue;
        dis[u] = tem;
        for(int i = head[u][0]; i; i = nxt[i][0]) {
            int v = to[i][0];
            if(vis[v])continue;
            q.push(v);
            vis[v] = true;
        }
    }
}


int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld%lld%d",&ad[i],&ap[i],&r);
        dis[i] = ap[i];
        for(int j = 1; j <= r; j++) {
            scanf("%d",&x);
            add(x,i,0);
            add(i,x,1);
        }
    }
    SPFA();
    printf("%lld",dis[1]);
    return 0;
}
View Code
posted @ 2019-05-16 20:17  Mogeko  阅读(184)  评论(0编辑  收藏  举报