【BZOJ3875】【Ahoi2014&Jsoi2014】骑士游戏(SPFA+DP)

传送门

简单题

如果我们把分裂看成连边
那么可以得到dpdp方程:f[i]=min(k[i],s[i]+Σf[to[i]])f[i]=min(k[i],s[i]+\Sigma {f[to[i]]})
spfaspfa就可以了

然而显然会构成正环,然后咕咕

考虑到如果我们更新了一个点,那么这个点的所有父亲(不是很准确,大概意思就是这个)
都会因此更新答案
那在把所有父亲也加到队列里跑就可以了

如果被卡spfaspfa用堆优化就可以了

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=200005;
int n,vis[N];
int s[N],f[N];
queue<int> q;
vector<int> e1[N],e2[N];
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		s[i]=read(),f[i]=read();
		int siz=read();
		for(int j=1;j<=siz;j++){
			int v=read();
			e1[i].push_back(v),e2[v].push_back(i);
		}
		q.push(i),vis[i]=1;
	}
	while(!q.empty()){
		int u=q.front();q.pop(),vis[u]=0;
		int tmp=s[u];
		for(int i=0;i<e1[u].size();i++){
			int v=e1[u][i];tmp+=f[v];
		}
		if(f[u]<=tmp)continue;f[u]=tmp;
		for(int i=0;i<e2[u].size();i++){
			int v=e2[u][i];
			if(!vis[v]){
				q.push(v),vis[v]=1;
			}
		}
	}
	cout<<f[1];
}
posted @ 2019-02-10 16:56  Stargazer_cykoi  阅读(86)  评论(0编辑  收藏  举报