洛谷:P6560 [SBCOI2020] 时光的流逝(博弈、拓扑序列)

时光流逝

洛谷:P6560 [SBCOI2020] 时光的流逝(博弈、拓扑序列)_第1张图片
题意:

  • 博弈论经典操作,一人动一下,谁不能动就输了。

思路:

  • 针对点,观察性质,找到必胜必败态。
  • 如果此题给的的 DAG(无环),显然我们会很好做,无脑拓扑反推即可,但题目没保证。
  • 如何处理环的问题?答案是稍稍修改我们拓扑的减度操作。

洛谷:P6560 [SBCOI2020] 时光的流逝(博弈、拓扑序列)_第2张图片
—— 摘自 duyi 的题解

一旦确定了一个节点的状态(必胜或必败),就立即加入到队列中,并且从此不再访问它。这样可以避免“环”对传递答案造成的不必要的“隔绝”。

拓扑的变式修改,很巧妙。

C o d e : Code: Code:

#include
#include
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define rfor(a,b,c) for(int a=b;a>=c;a--)
#define endl "\n"
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;

double DNF = 1e17;
const int N = 100010, M = 500010, MM = N;
int INF = 0x3f3f3f3f, mod = 998244353;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D, K;
int h[N], e[M], ne[M], idx;
int jl[N], ru[N], ty[N];

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void top_sort(int x, int y) {
	memcpy(ru, jl, sizeof jl);
	mem(ty, -1);
	queue<int> q;
	ty[y] = 0, q.push(y);
	forr(i, 1, n)if (ru[i] == 0 && i != y) {
		ty[i] = 0;
		q.push(i);
	}

	while (q.size())
	{
		int t = q.front();
		q.pop();
		for (int i = h[t]; ~i; i = ne[i]) {
			int j = e[i];
			if (ty[j] == -1) {
				ru[j]--;
				if (ty[t] == 0) {
					ty[j] = 1;
					q.push(j);
				}
				else if (ru[j] == 0) {
					ty[j] = 0;
					q.push(j);
				}
			}
		}
	}

	if (ty[x] == 0)ty[x] = -1;
	else if (ty[x] == -1)ty[x] = 0;
	cout << ty[x] << endl;
}

int main() {
	cinios;

	cin >> n >> m >> k;
	mem(h, -1);
	forr(i, 1, m) {
		int a, b;
		cin >> a >> b;
		add(b, a);
		jl[a]++;
	}

	while (k--) {
		int x, y;
		cin >> x >> y;
		top_sort(x, y);
	}

	return 0;
}
/*
*/

你可能感兴趣的:(图论)