P4042 [AHOI2014/JSOI2014]骑士游戏

题目背景

长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会

扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
题目描述

在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。

游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
输入格式

第一行包含一个整数N。

接下来N行,每行描述一个怪兽的信息;

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

输出一行一个整数,表示最少需要的体力值。
输入输出样例
输入 #1

4
4 27 3 2 3 2
3 5 1 2
1 13 2 4 2
5 6 1 2

输出 #1

26

说明/提示

首先用消耗4点体力用普通攻击,然后出现的怪兽编号是2,2和3。花费10点体力用法术攻击杀死两个编号为2的怪兽。剩下3号怪兽花费1点体力进行普通攻击。此时村庄里的怪兽编号是2和4。最后花费11点体力用法术攻击将这两只怪兽彻底杀死。一共花费的体力是4+5+5+1+5+6=26。

对于所有数据

分析

用 f[i] 表示杀死第 i 个怪兽所需的体力。

f[i] = min(k[i], ∑ f[k] + w[i] (通过 i 可以转移到 怪兽 k ));

令 f[i] 初始为 k[i], 无论怎么转移所花费的体力值都应小于直接魔法攻击所花费的体力
显然一个怪兽可以经过多次普通攻击重新变回同一只甚至更多的怪兽, 形成环状关系, 不能直接转移。
考虑用spfa转移。
对于每一只怪兽, 向它能生成的怪兽连边, 每次从队列中取出节点 t, 统计 t的所有出边指向的节点的花费
若 t 指向的节点的花费加上对 t 普通攻击的花费 小于 f[t] 则更新
f[t] 值 被更新, 就会引起能生成t的节点更新。 只要建反图把这些节点全压入队列中就行了。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int N = 2e5 + 10;
const int M = 1e7;
int e[M],ne[M],h1[N],h2[N],idx;
bool st[N];

int n;
long long f[N],s[N],k[N];
int x;

inline int read()
{
	int s = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
		s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}

inline long long readl() {
	long long s = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
    {
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
		s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}

void add(int h[], int a,int b)
{
    e[idx] = b; ne[idx]= h[a]; h[a] = idx++;
}

void spfa()
{
    queue <int> q;
    for(int i = n; i >= 1; i--)
    {
        st[i] = 1;
        q.push(i);
    }
    while(q.size())
    {
        int t = q.front();q.pop();
        st[t] = 0;
        long long sum = s[t];
        for(int i = h1[t]; ~i ; i = ne[i])
        {
            int j = e[i];
            sum += f[j];
        }
        if(sum >= f[t]) continue;
        f[t] = sum;
        for(int i = h2[t]; ~i ;i = ne[i])
        {
            int j = e[i];

           // printf("%d ---> %d\n",t,j);

            if(!st[j])
            {
                q.push(j);
                st[j] = 1;
            }
        }
    }

}


int main()
{
    scanf("%d",&n);
    memset(h1, -1, sizeof(h1));
    memset(h2, -1, sizeof(h2));
    for(int i = 1; i <= n; i++)
    {
        s[i] = readl(); k[i] = readl(); x = read();
        for(int j = 1; j <= x; j++)
        {
            int a;
            a = read();
            add(h1, i, a);
            add(h2, a, i);
        }
    }


    for(int i = 1; i <= n; i++) f[i] = k[i];
    spfa();

    printf("%lld",f[1]);
    return 0;
}
posted @ 2021-07-06 21:01  lyc_lb  阅读(85)  评论(0)    收藏  举报
-->
查看放大的地图   |   获取路线