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;
}