[SBCOI2020] 時光的流逝
題目背景
時間一分一秒的過著,伴隨著雪一同消融在了這個冬天,
或許,要是時光能停留在這一刻,該有多好啊。
......
“這是...我在這個小鎮的最後一個冬天了吧。”
“嗯,你可不能這輩子都呆在這個小鎮吧。外面的世界很大呢,很大很大...”
“唔...外面的世界...突然有點期待呢!”
“總有一天,你會走得很遠很遠。以後你可不要忘記這個小鎮那。”
“不會的,至少...這裡曾經是我最快樂的一段回憶呢!你也一定不要忘記我呀。”
“你看,這雪花。傳說,每當世界上有一份思念,便會化成一片雪花在這裡飄落。”
“那...以後你可一定要找到我的那片雪花啊......”
“嗯,不如我們一起在這個冬天創造最後一段回憶吧。”
“好呀,我們玩個遊戲吧......”
題目描述
這個遊戲是在一個有向圖(不保證無環)上進行的。每輪遊戲開始前,她們先在圖上選定一個起點和一個終點,並在起點處放上一枚棋子。
然後兩人輪流移動棋子,每次可以將棋子按照有向圖的方向移動至相鄰的點。
如果誰先將棋子移動至終點,那麼誰就勝利了。同樣,如果誰無法移動了,那麼誰就失敗了。
兩人輪流操作,請問,他們是否有必勝策略呢?
答案為一個整數 0
或 1
或 -1
,其中 1
表示(先手)有必勝策略,-1
表示後手有必勝策略,0
表示兩人均無必勝策略。
輸入格式
第\(\text{1}\)行有三個整數 \(n,m,q\) ,表示圖上有 \(n\) 個點, \(m\) 條邊,一共進行 \(q\) 輪遊戲。
接下來 \(m\) 行,每行輸入兩個數 \(u_i,v_i\) ,表示 \(u_i\) 到 \(v_i\) 有一條邊。
接下來 \(q\) 行,每行兩個數 \(x,y\) ,表示每輪操作的起點和終點。資料保證起點,終點不同
輸出格式
對於每輪遊戲,僅輸出一個整數 0
或 1
或 -1
,其中 1
表示先手有必勝策略,-1
表示後手有必勝策略,0
表示兩人均無必勝策略。
樣例 #1
樣例輸入 #1
7 7 1
1 2
2 3
3 4
4 5
3 6
7 5
6 7
1 5
樣例輸出 #1
1
樣例 #2
樣例輸入 #2
5 5 2
1 2
2 3
3 1
3 4
4 5
1 5
4 3
樣例輸出 #2
0
1
提示
樣例解釋 \(#1\)
為描述題意,假設兩人為 A(先手)和 B
如圖,A 先走,走到 \(2\),B 走到 \(3\),接下去 A 可以選擇走到 \(4\) 或 \(6\),若走到 \(4\),接下去 B 可以走到終點,故不可取。若選擇走到 \(6\),那麼 B 只能走到 \(7\),A 可以走到終點。所以 A 有必勝策略。
樣例解釋 \(#2\)
如圖,起點為 \(1\),終點為 \(5\) 時, A 和 B 會沿著 \(1-2-3-1\) 的順序輪流走。因為如果誰先走到 \(4\),那麼下一個人就可以走到終點。故誰都沒有必勝策略。
起點為 \(4\),終點為 \(3\) 時,A 先走到 \(5\),B 無路可走,故 B 失敗。
資料範圍
對於 \(10\%\) 的資料,保證圖是一條鏈。
對於 \(50\%\) 的資料,\(1\leq n\leq 10^3\),\(1\leq m\leq 2\times10^3\),\(1\leq q\leq 10\)。
對於 \(70\%\) 的資料,\(1\leq n\leq 10^5\),\(1\leq m\leq 2\times10^5\),\(1\leq q\leq 10\)。
對於 \(100\%\) 的資料,\(1\leq n\leq 10^5\),\(1\leq m\leq 5\times10^5\),\(1\leq q\leq 500\)。
思路
首先考慮輸出是 \(0\) 的情況,對於當前的人必輸,所以控制對方呆在迴圈之中,此時的答案是 \(0\),起點如果在距離終點 \(1\) 的位置那麼先手必勝,所以假設終點處是必敗(不存在起點等於終點的情況),\(st[ed]\) 為 \(-1\),如果有人無法移動,那麼這個人輸,在有向圖上無法移動,也就是出度為 \(0\),那麼先將出度為 \(0\) 的點和終點存入佇列,跑拓撲排序,如果上一個節點是必敗,那麼這個點無論是不是在環內,一定是必勝是狀態,如果上一個點是必勝的狀態,這個點不在環內的話就是必輸狀態,但如果這個點在環內,那麼他的狀態就不能現在確定,要透過其他的點來判斷或者 \(st[x]=0\)。至此,所有點的狀態都確定了,直接輸出就行,程式碼如下。
`
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n, m, q;
vector<int> g[N];
int ru[N];
int st[N], now[N];
void solve()
{
cin >> n >> m >> q;
while (m --)
{
int a, b;
cin >> a >> b;
g[b].push_back(a);
ru[a] ++;
}
while (q --)
{
int be, ed;
cin >> be >> ed;
queue<int> qu;
for (int i = 1; i <= n; i ++)
{
now[i] = ru[i];
if (!now[i] || i == ed)
{
st[i] = -1;
qu.push(i);
}
else st[i] = 0;
}
while (qu.size())
{
int it = qu.front();
qu.pop();
for (auto x : g[it])
{
if (!st[x])
{
now[x] --;
if (st[it] == -1)
{
st[x] = 1;
qu.push(x);
}
else if (!now[x])
{
st[x] = -1;
qu.push(x);
}
}
}
}
cout << st[be] << "\n";
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
}
`