BZOJ3875: [Ahoi2014&Jsoi2014]骑士游戏

【传送门:BZOJ3875


简要题意:

  给出n种怪物,每种怪物都带有三个值,S[i],K[i],R[i],分别表示对他使用普通攻击的花费,使用魔法攻击的花费,对他使用普通攻击后生成的其他怪物。

  每种怪物只能用法术攻击来消灭,用普通攻击只能将怪物变成其他怪物

  当前第一种怪物来了,请问将怪物完全消灭的最小花费


题解:

  首先一看就像DP,设f[i]为消灭第i种怪物的最小花费,可以列出方程:f[i]=min(K[i],∑f[j](将第i种怪物能生成的怪物消灭的最小花费总和))

  但是这种方法显然会出现环,那么我们就用近似SPFA的方法来解决这个问题

  首先将每种怪物放入队列,然后设d=s[x]+∑f[j],如果d<f[x]的话,就更新f[x]

  但是我们不但要更新f[x],还要更新能够生成第x种怪物的怪物,所以我们就要把这些怪物也放进队列里(如果这些怪物本身就在队列里的话,就不用)

  最后输出f[1]就可以了

  PS:要用STL容器来保存怪物生成怪物的信息(不然会爆空间),而且最好用queue来保存队列


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
queue<int>q;
vector<int>c[210000];
vector<int>cd[210000];
bool v[210000];
LL f[210000],s[210000],k[210000];
int main()
{
    int n;
    scanf("%d",&n);
    int head=1,tail=1;int r;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&s[i],&k[i]);
        f[i]=k[i];
        scanf("%d",&r);
        q.push(i);v[i]=true;
        while(r--)
        {
            int x;
            scanf("%d",&x);
            c[i].push_back(x);
            cd[x].push_back(i);
        }
    }
    while(q.empty()==0)
    {
        int x=q.front();
        LL d=s[x];
        for(int i=0;i<c[x].size();i++) d+=f[c[x][i]];
        if(f[x]>d)
        {
            f[x]=d; 
            for(int i=0;i<cd[x].size();i++)
            {
                if(v[cd[x][i]]==false)
                {
                    v[cd[x][i]]=true;
                    q.push(cd[x][i]);
                }
            }
        }
        q.pop();
        v[x]=false;
    }
    printf("%lld\n",f[1]);
    return 0;
}

 

posted @ 2017-11-29 13:24  Star_Feel  阅读(149)  评论(0编辑  收藏  举报