BZOJ3875 AHOI2014/JSOI2014骑士游戏(动态规划)

  容易想到设f[i]为杀死i号怪物所消耗的最小体力值,由后继节点更新。然而这显然是有后效性的,正常的dp没法做。

  虽然spfa已经死了,但确实还是挺有意思的。只需要用spfa来更新dp值就可以了。dij看起来也差不多。

  更新部分写的看起来就很慢很能优化一波,在luogu上T一个点,然而实在太懒了就算了吧(

  记得我们老师说过某位学长省选前几乎什么省选算法都不会,然后当场切掉了这题,然后进了省队,然后拿了cu,最后进了pku。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define N 200010
#define ll long long
#define inf 100000000000000000
ll read()
{
    ll x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,q[N];
ll f[N];
bool flag[N];
struct data
{
    ll x,y;
    vector<int> from,to;
}a[N];
int inc(int &x){x++;if (x>n+1) x-=n+1;return x;}
bool cmp(const int &a,const int&b)
{
    return f[a]<f[b];
}
void spfa()
{
    int head=0,tail=n;for (int i=1;i<=n;i++) q[i]=i,flag[i]=1,f[i]=a[i].y;
    sort(q+1,q+n+1,cmp);
    do
    {
        int x=q[inc(head)],s=a[x].from.size();flag[x]=0;
        for (int i=0;i<s;i++)
        {
            int y=a[x].from[i];
            int t=a[y].to.size();ll sum=a[y].x;
            for (int j=0;j<t;j++)
            {
                sum+=f[a[y].to[j]];
                if (sum>f[y]) break;
            }
            if (sum<f[y])
            {
                f[y]=sum;
                if (!flag[y]) q[inc(tail)]=y,flag[y]=1;
            }
        }
    }while (head!=tail);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3875.in","r",stdin);
    freopen("bzoj3875.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++)
    {
        a[i].x=read(),a[i].y=read();
        int t=read();
        while (t--)
        {
            int x=read();
            a[x].from.push_back(i),
            a[i].to.push_back(x);
        }
    }
    spfa();
    cout<<f[1];
    return 0;
}

 

posted @ 2018-10-06 23:10  Gloid  阅读(198)  评论(0编辑  收藏  举报