1. 程式人生 > >BZOJ3875 AHOI2014/JSOI2014騎士遊戲(動態規劃)

BZOJ3875 AHOI2014/JSOI2014騎士遊戲(動態規劃)

老師 con ack 有意思 mes cstring cto -s bzoj3875

  容易想到設f[i]為殺死i號怪物所消耗的最小體力值,由後繼節點更新。然而這顯然是有後效性的,正常的dp沒法做。

  雖然spfa已經死了,但確實還是挺有意思的。只需要用spfa來更新dp值就可以了。

  記得我們老師說過某位學長省選前幾乎什麽省選算法都不會,然後當場切掉了這題,然後進了省隊,然後拿了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; }

BZOJ3875 AHOI2014/JSOI2014騎士遊戲(動態規劃)