洛谷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;
}