【53.90】【BZOJ 3875】 [Ahoi2014]骑士游戏

Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 564 Solved: 304
[Submit][Status][Discuss]
Description

【故事背景】
长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会
扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
【问题描述】
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻
击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入
侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
Input

第一行包含一个整数N。
接下来N行,每行描述一个怪兽的信息;
其中第i行包含若干个整数,前三个整数为Si,Ki和Ri,表示对于i号怪兽,
普通攻击需要消耗Si的体力,法术攻击需要消耗Ki的体力,同时i号怪兽死亡后会产生Ri个新的怪兽。表示一个新出现的怪兽编号。同一编号的怪兽可以出现多个。
Output

输出一行一个整数,表示最少需要的体力值。

Sample Input

4

4 27 3 2 3 2

3 5 1 2

1 13 2 4 2

5 6 1 2
Sample Output

26
HINT

【样例说明】

首先用消耗4点体力用普通攻击,然后出现的怪兽编号是2,2和3。花费

10点体力用法术攻击杀死两个编号为2的怪兽。剩下3号怪兽花费1点体力进

行普通攻击。此时村庄里的怪兽编号是2和4。最后花费11点体力用法术攻击

将这两只怪兽彻底杀死。一共花费的体力是4+5+5+1+5+6=26。

【数据范围】

2<=N<=2*10^5,1<=Ri,Sigma(Ri)<=10^6,1<=Ki,Si<=5*10^14
Source

By 佚名上传

题解


设f[i]表示消灭i这个怪物所需要的最小花费。
f[i]一开始等于g[i];
设g[i]为用物理攻击消灭i号怪物所需的花费。
g[i]一开始等于s[i] + ∑k[i的出度];
则f[i] = min(k[i],∑f[i的出度]);

g[i]一开始等于s[i] + ∑k[i的出度];
显然g[i]这个状态不可能总是正确的。则我们需要尝试更新每一个g[i];
更新的方式是从尾往前更新。
如果发现某个x它的g值小于f值;则,我们显然可以更新那些出度有x的点三设为before的g值了。
即g[before]-=f[x];g[before]+=g[x];
因为更新了before的信息。则before之前的信息也可能更改了。则把它加进去。继续更新。
这个过程很像SPFA的更新过程。
用spfa去做吧。
建边的时候建个反图。这样就能知道某个节点它的前驱是啥了。

代码

#include <cstdio>
#include <vector>
#include <queue>

using namespace std;

const int MAXN = 2 * 1e5 + 10;

int n;
long long si[MAXN],ki[MAXN];
vector <int> zheng[MAXN], fan[MAXN];
long long f[MAXN], g[MAXN];
queue <int> dl;
bool inque[MAXN] = { 0 };

void spfa()
{
    while (!dl.empty())
    {
        int x = dl.front();
        inque[x] = false;
        dl.pop();
        if (g[x] >= f[x])
            continue;
        int len = fan[x].size();
        for (int i = 0; i <= len - 1; i++)
        {
            int before = fan[x][i];
            g[before] -= f[x];
            g[before] += g[x];
            if (!inque[before])
            {
                inque[before] = true;
                dl.push(before);
            }
        }
        f[x] = g[x];//因为g[x] < f[x]则f[x]可以更新了
    }
}

int main()
{
//  freopen("F:\rush.txt", "r", stdin);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        dl.push(i);
        inque[i] = true;
        scanf("%lld%lld", &si[i], &ki[i]);
        int num;
        scanf("%d", &num);
        for (int j = 1; j <= num; j++)
        {
            int y;
            scanf("%d", &y);
            zheng[i].push_back(y);
            fan[y].push_back(i);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        f[i] = ki[i];
        g[i] = si[i];
        int len = zheng[i].size();
        for (int j = 0; j <= len - 1; j++)//这只是初值。之后会更新
            g[i] += ki[zheng[i][j]];
    }
    spfa();
    printf("%lld
", f[1]);
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/7632210.html