1. 程式人生 > 其它 >[AHOI2014/JSOI2014]騎士遊戲

[AHOI2014/JSOI2014]騎士遊戲

題目連結

問題分析

如果這個圖是個DAG,那麼問題就簡單了。按照拓撲序的逆序做DP即可。

那麼問題就在於環。於是藉助SPFA的想法,更新某個節點後向它的父親拓展,直至不能更新。

這裡需要注意把可能要被更新的節點入隊,而不是確定要被更新的點,否則可能TLE。具體見參考程式。

參考程式

#include <cstdio>

const int Maxn = 200010;
const int MaxR = 1000010;
int N, R, x;
long long S[Maxn], K[Maxn], s;
struct edge {
	int To, Next, Type;
	edge() {}
	edge(int _To, int _Next, int _Type) : To(_To), Next(_Next), Type(_Type) {}
};
edge Edge[MaxR << 1];
int Start[Maxn], Space;
int Head, Tail, Queue[Maxn], InQ[Maxn];
long long Dis[Maxn];

int main() {
	scanf("%d", &N);
	for (int i = 1; i <= N; ++i) {
		scanf("%lld%lld", &S[i], &K[i]);
		scanf("%d", &R);
		for (int j = 1; j <= R; ++j) {
			scanf("%d", &x);
			Edge[++Space] = edge(x, Start[i], 1); Start[i] = Space;
			Edge[++Space] = edge(i, Start[x], 2); Start[x] = Space;
		}
	}
	Head = Tail = 0;
	for (int i = 1; i <= N; ++i) {
		Dis[i] = K[i];
		Queue[Tail] = i;
		++Tail; if (Tail >= Maxn) Tail = 0;
		InQ[i] = 1;
	}
	while (Head != Tail) {
		s = S[Queue[Head]];
		for (int t = Start[Queue[Head]]; t != 0; t = Edge[t].Next) {
			if (Edge[t].Type == 2) continue;
			s += Dis[Edge[t].To];
		} 
		if (s < Dis[Queue[Head]]) { //如果被更新了,就把它的所有父親都放入佇列
			Dis[Queue[Head]] = s;
			for (int t = Start[Queue[Head]]; t != 0; t = Edge[t].Next) {
				if (Edge[t].Type == 1) continue;
				if (InQ[Edge[t].To] == 1) continue;
				Queue[Tail] = Edge[t].To;
				++Tail; if (Tail >= Maxn) Tail = 0;
				InQ[Edge[t].To] = 1;
			}
		}
		InQ[Queue[Head]] = 0;
		++Head; if (Head >= Maxn) Head = 0;
	}
	printf("%lld\n", Dis[1]);
	return 0;
}