塔式破碎机 - 与除数的nim游戏变化

时间:2017-01-13 20:48:41

标签: algorithm math game-theory nim-game

我遇到过一款名为Tower Breakers的游戏,它似乎是nim game的变体。

  • 有两名球员,球员1和球员2.
  • 最初有n个塔,其中每个塔的高度为mnm为正整数。
  • 玩家1开始,然后他们轮流移动。
  • 在每个回合中,玩家可以选择一个高度为x > 1的塔,并将其高度降低为正整数y,其中1 <= y < xy均分x 1}}。
  • 如果当前玩家无法进行任何移动,则输掉比赛。

是否有一些获胜策略?如果塔在开始时没有相同的高度怎么办?

2 个答案:

答案 0 :(得分:1)

一般情况

这确实可以像nim game一样解决,但使用不同的nimber定义。

在原始游戏中,塔的nimber被简单地定义为它的高度。

在此变体中,T高度为h(T) = x = p₁ˢ¹ … pₖˢᵏpᵢn(T) = s₁ + … + sₖ 的塔的nimber是

n

L = (T₁, …, Tₙ)n(L) = n(T₁) ⊕ … ⊕ n(Tₙ) 列表中的nimber通常是

n(L) > 0

如果你的回合开始时nimber是0,那么假设其他玩家玩得很好,你就会失败。

否则,您只需要进行一次移动,使nimber变为零。

你可以这样做,因为如果Tₙ然后有一个塔,那么我们假设n(Tₙ) ⊕ n(L) < n(L)不会失去概括,这样n(L)。< / p>

这样的塔存在:1的最左边的位是Tₙ,因为某个塔n(Tₙ) ⊕ n(L)在该位位置有一个1。做n(Tₙ)你会杀掉那个1并且不会改变n(L)的更重要的位,因为它是n(Tₙ) ⊕ n(L)的最左边的位。所以Tₙ更小。

然后,您只需将Tₙ'修改为n(Tₙ') = n(Tₙ) ⊕ n(L),以便n(L') = n(T₁) ⊕ … ⊕ n(Tₙ') = n(T₁) ⊕ … ⊕ n(Tₙ) ⊕ n(L) = n(L) ⊕ n(L) = 0 ,从而

x' = p₁ˢ¹ … pₗ₋₁ˢˡ⁻¹ pₗᵈ

此移动始终是可行的,例如使用l <= k0 < d <= sₗ将高度降低到s₁ + … + sₗ₋₁ + d = n(Tₙ) ⊕ n(L),以便x'x按结构划分x' < xn(L)因此他们不同。

一旦nimber为零,无论其他玩家的动作如何,它都会影响该塔的nimber,然后总xor function nimber(num) { var n = 0; for (var i=2; i<=num; ++i) while(num % i == 0) { ++n; num /= i; } return n; } function change(tower, newHeight, oldHeight, txt) { tower.textContent = newHeight; totalNimber ^= tower.dataset.nimber; tower.dataset.nimber = nimber(newHeight); totalNimber ^= tower.dataset.nimber; log.textContent += " " + txt + " the height of the " + tower.getAttribute('data-index') + "-th tower from " + oldHeight + " to " + newHeight + ".\n"; if (newHeight == 1) tower.removeEventListener('click', playerMove); } function end(txt) { log.textContent += " " + txt; playerMove = Function.prototype; } function prePlayerMove() { log.textContent += "Your turn. nimber = " + totalNimber + ".\n"; for (var i=0; i<n; ++i) { var height = +towers.children[i].textContent; if (height != 1) return; } end("You lose"); } function playerMove() { var oldHeight = +this.textContent, newHeight; while(!newHeight || newHeight <= 0 || oldHeight%newHeight || newHeight == oldHeight) newHeight = +prompt("Current tower height is " + oldHeight + ". Enter new height"); change(this, newHeight, oldHeight, "You reduce"); pcMove(); } function pcMove() { log.textContent += "PC's turn (nimber = " + totalNimber + ").\n"; if (totalNimber == 0) { // Oh shit. for (var i=0; i<n; ++i) { var oldHeight = +towers.children[i].textContent; if (oldHeight != 1) for (var j=2; j<=oldHeight; ++j) if (oldHeight % j == 0) { var newHeight = oldHeight / j; change(towers.children[i], newHeight, oldHeight, "PC reduces"); prePlayerMove(); return; } } end("PC loses"); } else { for (var i=0; i<n; ++i) { var tower = towers.children[i]; var objective = tower.dataset.nimber ^ totalNimber; if (objective < tower.dataset.nimber) { var oldHeight = +tower.textContent; var newHeight = oldHeight; var nim = 0; for (var j=2; j<=newHeight && nim<objective; ++j) { while(newHeight % j == 0 && nim<objective) { ++nim; newHeight /= j; } } newHeight = oldHeight / newHeight; if (nimber(newHeight) != objective) throw Error('Fatal error'); change(tower, newHeight, oldHeight, "PC reduces"); break; } } prePlayerMove(); } } var n, m; while(!Number.isInteger(n) || n < 0) n = +prompt("Number of towers"); while(!Number.isInteger(m) || m < 0) m = +prompt("Height of each tower"); var totalNimber = 0; var towers = document.getElementById('towers'); var log = document.getElementById('log'); for (var i=0; i<n; ++i) { var nim = nimber(m); totalNimber ^= nim; var tower = document.createElement('div'); tower.dataset.index = i+1; tower.dataset.nimber = nim; tower.textContent = m; tower.addEventListener('click', playerMove); towers.appendChild(tower); } pcMove();将不再为零。然后重复相同的策略。

特殊情况

在所有塔具有相同高度的特定情况下,

  • 如果偶数塔或塔的高度为1,则总的nimber将为零,因此如果玩得最佳,则玩家2将获胜。
  • 否则,总的nimber将为非零,因此如果玩得最佳,玩家1将获胜。

事实上,这可以在不使用nimbers的情况下显示:

  • 如果有偶数塔,则玩家2可以成对分组。他想要保持的不变量是每对中的两个塔都有相同的高度。每当玩家1移动时,这种变体将会中断。然后玩家2只需要对该对中的另一个塔进行相同的移动(这将是一个有效的移动,否则玩家1无法完成它)。最终所有塔都将达到高度1,玩家2将获胜。

  • 如果有奇数个塔(高度> 1),玩家1可以将最后一个塔的高度减少到1.实际上,这就像消除那个塔一样。所以现在轮到玩家了,但是可玩的塔的数量会是均匀的。所以前一种情况适用,而玩家1将获胜。

播放

您可以在以下代码段中播放:

&#13;
&#13;
#towers > div {
  display: inline-block;
  border: 1px solid;
  cursor: pointer;
  margin: 5px;
  padding: 5px;
}
&#13;
<div id="towers"></div>
<pre id="log"></pre>
&#13;
List
&#13;
&#13;
&#13;

答案 1 :(得分:1)

这里是塔式破碎机的答案(高度相等)。

答案

  • 如果M为1,则第二位玩家将获胜。
  • 如果N是偶数(N % 2 == 0)且M不是1,则第二位玩家将获胜。
  • 如果N为奇数(N % 2 == 1)且M不为1,则第一位玩家将获胜。

这是我的C ++代码。 (它已被接受)

#include <bits/stdc++.h>
using namespace std;
int Q, N, M;
int main() {
    cin >> Q;
    while(Q--) {
        cin >> N >> M;
        if(M == 1 || N % 2 == 0) cout << 2 << endl;
        else cout << 1 << endl;
    }
}

为什么它是正确的?

  • 如果M为1,很明显第二位玩家将获胜,因为第一位玩家无法移动。
  • 如果N是偶数,则第二位玩家可以对第一位玩家进行相同的操作。例如,如果第一位玩家移动{4, 4, 4, 4} -> {2, 4, 4, 4},则第二位玩家可以移动{2, 4, 4, 4} -> {2, 2, 4, 4}。最后,第二位玩家可以{1, 1, 1, ..., 1},所以第二位玩家可以获胜。
  • 如果N是奇数,第一个玩家可以将第一个塔的高度减少到1,所以你可以返回到&#34; N是偶数&#34;案件。所以,你可以证明第一个玩家获胜。
  • 所以,答案是正确的。