題目跳轉
思路:這道題可能跟博弈論有一點關係,沒有學習過博弈論做起來應該問題也不大。思考一個問題,先手必勝的前提是什麼?
有關更多的內容可以前往:淺談有向無環圖
- 先手必勝的前提是,在任何一種局面下,先手都有至少一種操作可以使後手處於必敗的局面。
- 若先手進行任何操作後,後手都可以選擇必勝的操作,則先手無法必勝。
- 如果當前玩家無法進行任何操作,那麼對手獲勝。
整體的思路就是透過遞迴不斷搜尋每一種決策情況,判斷是否存在必勝的策略。
具體的實現方法:
建立兩個函式,名為first
和second
。
first(x, y)
函式返回當兩位玩家分別選擇數字x
和y
時,先手是否必勝。second(x, y)
函式返回當兩位玩家分別選擇數字x
和y
時,後手是否必勝。
兩個函式來回交替呼叫對方,即在first(x, y)
函式中呼叫second(x, y)
函式,在second(x, y)
中呼叫first(x, y)
。如果存在必勝的策略,返回true
,否則返回false
。若先手玩家無法再進行操作時,也返回false。
時間複雜度分析:本道題目將透過深度優先搜尋DFS的方式來實現,每一層遞迴模擬某一位玩家的兩個決策(將數字乘二或將數字除以三)。因此本道題目的時間複雜度大致為\(O(2^d)\),其中\(d\)表示遞迴的深度。考慮題目資料範圍\(1 <= x, y <= 1000\),遞迴深度約為\(\log2(\frac{x+y}{2})\),完全可以在限定時間內透過所有的測試點。
參考程式碼一:
#include <iostream>
#include <cstring>
using namespace std;
int vis[1005];
bool last(int x, int y);
bool first(int x, int y){
bool isEnd, p1, p2;
isEnd = p1 = p2 = true;
if (x * 2 <= 1000 && !vis[x * 2]){
isEnd = false;
vis[x * 2] = 1;
p1 = last(x*2, y);
vis[x * 2] = 0;
}
if (x % 3 == 0 && !vis[x / 3]){
isEnd = false;
vis[x / 3] = 1;
p2 = last(x / 3, y);
vis[x / 3] = 0;
}
if (isEnd) return false;
// 如果後手有一條方案會必死,那麼先手就一定贏。
return !(p1 && p2);
}
bool last(int x, int y){
bool isEnd, p1, p2;
isEnd = p1 = p2 = true;
if (y * 2 <= 1000 && !vis[y * 2]){
isEnd = false;
vis[y * 2] = 1;
p1 = first(x, y * 2);
vis[y * 2] = 0;
}
if (y % 3 == 0 && !vis[y / 3]){
isEnd = false;
vis[y / 3] = 1;
p2 = first(x, y / 3);
vis[y / 3] = 0;
}
if (isEnd) return false;
return !(p1 && p2);
}
int main(){
int t, x, y;
cin >> t;
while(t--){
memset(vis, 0, sizeof vis);
cin >> x >> y;
if (first(x, y)) cout << "Macw07" << endl;
else cout << "Penelope_77" << endl;
}
return 0;
}
參考程式碼二:
decision(r)
函式返回當兩位玩家分別選擇數字val[0]
和val[1]
時,r
選手(先手為0,後手為1)是否必勝。
#include <iostream>
#include <cstring>
using namespace std;
int vis[1005];
int val[5];
bool decision(int r){
bool isEnd, p1, p2;
isEnd = p1 = p2 = true;
if (val[r] * 2 <= 1000 && !vis[val[r] * 2]){
isEnd = false;
val[r] *= 2;
vis[val[r]] = 1;
p1 = decision(!r);
vis[val[r]] = 0;
val[r] /= 2;
}
if (val[r] % 3 == 0 && !vis[val[r] / 3]){
isEnd = false;
val[r] /= 3;
vis[val[r]] = 1;
p2 = decision(!r);
vis[val[r]] = 0;
val[r] *= 3;
}
if (isEnd) return false;
return !(p1 && p2);
}
int main(){
int t, x, y;
cin >> t;
while(t--){
memset(vis, 0, sizeof vis);
cin >> x >> y;
val[0] = x;
val[1] = y;
if (decision(0)) cout << "Macw07" << endl;
else cout << "Penelope_77" << endl;
}
return 0;
}