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