Description
【故事背景】
长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会
扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
【问题描述】
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻
击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入
侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
题解:
这题一开始一直在想一种神奇的贪心,然后发现不行,
接着又发现可以用贪心的思想来DP,
f[i]表示打败i的最小花费,d[i]表示打败i及其相关联的怪兽的最小花费。
初始化用贪心思想,f[i]=直接打死怪兽的花费,d[i]=普通打败怪兽i在用特殊攻击打与相关连的怪兽。
然后我们用类似spfa的方法来跑dp,每个怪兽向与它相关联的怪兽反向建一条边。
然后就类似贪心来做,yy就好。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=201000;
long long n;
long long a[N],b[N];
struct node{
long long x,y,next;
}sa[N*20];long long len=0,first[N];
struct node1{
long long x,y,next;
}ss[N*20];long long tot=0,next[N];
void add(long long x,long long y)
{
len++;
sa[len].x=x;
sa[len].y=y;
sa[len].next=first[x];
first[x]=len;
}
void add1(long long x,long long y)
{
tot++;
ss[tot].x=x;
ss[tot].y=y;
ss[tot].next=next[x];
next[x]=tot;
}
long long f[N],d[N];
queue<long long>q;
bool tf[N];
void spfa()
{
//memset(tf,0,sizeof(tf));
while(!q.empty())
{
//prlong longf("!");
long long x=q.front();q.pop();
tf[x]=0;
if(d[x]>=f[x]) continue;
for(long long i=next[x];i!=-1;i=ss[i].next)
{
long long y=ss[i].y;
d[y]-=f[x];d[y]+=d[x];
if(!tf[y])
q.push(y),tf[y]=1;
}
f[x]=d[x];
//tf[x]=0;
}
}
int main()
{
scanf("%lld",&n);
long long x,y,sum,yu;
memset(first,-1,sizeof(first));
memset(next,-1,sizeof(next));
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&a[i],&b[i],&sum);
for(long long j=1;j<=sum;j++)
{
scanf("%lld",&x);
add(i,x);add1(x,i);
}
}
for(long long i=1;i<=n;i++)
q.push(i),tf[i]=1;
for(long long i=1;i<=n;i++)
{
f[i]=b[i];
d[i]=a[i];
for(long long j=first[i];j!=-1;j=sa[j].next)
{
long long y=sa[j].y;
//prlong longf("!%d\n",y);
d[i]+=b[y];
}
}
//prlong longf("!");
//prlong longf("%d\n",d[1]);
spfa();
printf("%lld\n",d[1]);
}