1. 程式人生 > >BZOJ3875: [Ahoi2014&Jsoi2014]騎士遊戲

BZOJ3875: [Ahoi2014&Jsoi2014]騎士遊戲

main 題意 pty 最小花費 true false return 隊列 long

【傳送門: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; }

BZOJ3875: [Ahoi2014&Jsoi2014]騎士遊戲