我遇到过一款名为Tower Breakers的游戏,它似乎是nim game的变体。
n
个塔,其中每个塔的高度为m
,n
和m
为正整数。x > 1
的塔,并将其高度降低为正整数y
,其中1 <= y < x
和y
均分x
1}}。是否有一些获胜策略?如果塔在开始时没有相同的高度怎么办?
答案 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 <= k
和0 < d <= sₗ
将高度降低到s₁ + … + sₗ₋₁ + d = n(Tₙ) ⊕ n(L)
,以便x'
。 x
按结构划分x' < x
,n(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();
将不再为零。然后重复相同的策略。
在所有塔具有相同高度的特定情况下,
事实上,这可以在不使用nimbers的情况下显示:
如果有偶数塔,则玩家2可以成对分组。他想要保持的不变量是每对中的两个塔都有相同的高度。每当玩家1移动时,这种变体将会中断。然后玩家2只需要对该对中的另一个塔进行相同的移动(这将是一个有效的移动,否则玩家1无法完成它)。最终所有塔都将达到高度1,玩家2将获胜。
如果有奇数个塔(高度> 1),玩家1可以将最后一个塔的高度减少到1.实际上,这就像消除那个塔一样。所以现在轮到玩家了,但是可玩的塔的数量会是均匀的。所以前一种情况适用,而玩家1将获胜。
您可以在以下代码段中播放:
#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;
答案 1 :(得分:1)
这里是塔式破碎机的答案(高度相等)。
(N % 2 == 0)
且M不是1,则第二位玩家将获胜。(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;
}
}
{4, 4, 4, 4} -> {2, 4, 4, 4}
,则第二位玩家可以移动{2, 4, 4, 4} -> {2, 2, 4, 4}
。最后,第二位玩家可以{1, 1, 1, ..., 1}
,所以第二位玩家可以获胜。