P6560 [SBCOI2020] 时光的流逝 (博弈,反向建图,拓扑排序

洛谷P6560 [SBCOI2020] 时光的流逝
题意:
给定一个有向图(可能有环),给定起点和终点,两个人玩游戏,一人走一步,先到达终点的人赢或者先无法移动的人输
思路:
题解
因为是终点和叶子节点是必败态,这是确定的,因此我们可以倒着搞
建反图跑拓扑排序更新节点胜负态
存在环就很难搞,拓扑排序的时候是无法进入环的,那么环上的点就难以确定胜负态
更新思想有点类似于点权这个题
就是如果当前节点胜负态是确定的,就可以去更新其他节点,我们就把他 p u s h push push 到队列中,而不是按照拓扑排序的顺序来
这样环上的点也可以进行更新
更新规则:
如果一个节点的后继节点是必败点,那么它是必胜点
如果一个点的后继节点全是必胜点,那么它是必败点
code:

#include
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> e[maxn];
int in[maxn], deg[maxn], f[maxn];
int s, ed;

void topsort(){
	queue <int> q;
	for(int i = 1; i <= n; ++i) {
		in[i] = deg[i];
		if(!in[i] || i == ed) f[i] = -1, q.push(i);
		else f[i] = 0;
	}
	while(!q.empty()){
		int x = q.front();q.pop();
		for(int to : e[x]){
			if(f[to] != 0) continue;// 状态已经确定
			in[to]--;
			if(f[x] == -1) {// 因为是反图,x是必败的,那么to一定是必胜的 
				f[to] = 1;q.push(to);
			} 
			else if(!in[to]){// 反图,入度为0,to的后继节点状态全部确定了,并且一定没有必败点,如果有必败点,那么在之前就to就会被更新为必胜点
				f[to] = -1;// to的后继节点x中全是必胜点,那么它就是必败点 
				q.push(to); 
			}
		}
	}
	cout << f[s] << endl; 
}
void work()
{
	int q;cin >> n >> m >> q;
	for(int i = 1; i <= m; ++i){
		int x, y;cin >> x >> y;e[y].push_back(x);deg[x]++;
	}
	while(q--){
		cin >> s >> ed;
		topsort();
	}
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

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