兩名士兵用 n 張牌(1..n,無重複)玩「戰爭」遊戲:每輪各出頂牌,大牌勝,將兩張牌按「先對手牌、再自己牌」順序置於自己牌堆底。一方牌盡則輸。n ≤ 10,狀態空間極小,直接模擬並檢測循環即可。
q1, q2,元素為卡牌值(1..n)。x = q1.pop(), y = q2.pop();若 x > y 則 q1.push(y), q1.push(x),否則 q2.push(x), q2.push(y)。n ≤ 10,總排列數 n! ≤ 3,628,800,但實際可達狀態遠少。兩種檢測方法:
set 記錄 q1序列 + "|" + q2序列,遇到重複即循環。嚴格正確,額外 O(step * n log n) 開銷。#includeusing namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; if (!(cin >> n)) return 0; queue q1, q2; int k1, x; cin >> k1; for (int i = 0; i < k1; ++i) { cin >> x; q1.push(x); } int k2; cin >> k2; for (int i = 0; i < k2; ++i) { cin >> x; q2.push(x); } const int MAX_STEPS = 1000000; // 經驗值,n=10 實際循環週期極短 int steps = 0; while (!q1.empty() && !q2.empty() && steps < MAX_STEPS) { int x = q1.front(); q1.pop(); int y = q2.front(); q2.pop(); ++steps; if (x > y) { q1.push(y); q1.push(x); } else { q2.push(x); q2.push(y); } } if (q1.empty()) { cout << steps << " 2\n"; // 玩家 2 勝 } else if (q2.empty()) { cout << steps << " 1\n"; // 玩家 1 勝 } else { cout << -1 << "\n"; // 循環 } return 0; }
| 指標 | 值 | 說明 |
|---|---|---|
| 時間複雜度 | O(MAX_STEPS) | 每步 O(1) 隊列操作,MAX_STEPS=1e6 極快 |
| 空間複雜度 | O(n) | 兩個隊列共存 n 張牌 |
| 實際循環週期 | < 10000 | n=10 時實測最大週期約幾千步,1e6 絕對安全 |
// 替換 while 條件部分 setseen; auto encode = [&](queue a, queue b) { string s; while (!a.empty()) { s += to_string(a.front()); a.pop(); s += ','; } s += '|'; while (!b.empty()) { s += to_string(b.front()); b.pop(); s += ','; } return s; }; while (!q1.empty() && !q2.empty()) { string state = encode(q1, q2); if (seen.count(state)) { cout << -1 << "\n"; return 0; } seen.insert(state); // ... 同前模擬步驟 }