【題解】A18536.星光交錯的律動

Macw發表於2024-03-18

題目跳轉

思路:這道題可能跟博弈論有一點關係,沒有學習過博弈論做起來應該問題也不大。思考一個問題,先手必勝的前提是什麼?

有關更多的內容可以前往:淺談有向無環圖

  • 先手必勝的前提是,在任何一種局面下,先手都有至少一種操作可以使後手處於必敗的局面。
  • 若先手進行任何操作後,後手都可以選擇必勝的操作,則先手無法必勝。
  • 如果當前玩家無法進行任何操作,那麼對手獲勝。

整體的思路就是透過遞迴不斷搜尋每一種決策情況,判斷是否存在必勝的策略。

具體的實現方法:

建立兩個函式,名為firstsecond

  1. first(x, y)函式返回當兩位玩家分別選擇數字xy時,先手是否必勝。
  2. second(x, y)函式返回當兩位玩家分別選擇數字xy時,後手是否必勝。

兩個函式來回交替呼叫對方,即在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;
}

參考程式碼二:

  1. 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;
}

相關文章