巴什博奕(Bash_Game)
一、定義
只有一堆n個物品,兩個人輪流從這堆物品中取物, 規定每次至少取一個,最多取m個。最後取光者得勝。
二、分析
我們從最簡單的情景開始分析
當石子有1−m1−m個時,毫無疑問,先手必勝
當石子有m+1m+1個時,先手無論拿幾個,後手都可以拿乾淨,先手必敗
當石子有m+2−2mm+2−2m時,先手可以拿走幾個,剩下m+1m+1個,先手必勝
我們不難發現,面臨m+1m+1個石子的人一定失敗。
這樣的話兩個人的最優策略一定是通過拿走石子,使得對方拿石子時還有m+1m+1個
我們考慮往一般情況推廣
-
設當前的石子數為n=k∗(m+1)+rn=k∗(m+1)+r
先手會首先拿走rr個,接下來假設後手拿走xx個,先手會拿走m+1−xm+1−x個,這樣博弈下去後手最終一定失敗
-
設當前的石子數為n=k∗(m+1)n=k∗(m+1)
假設先手拿xx個,後手一定會拿m+1−xm+1−x個,這樣下去先手一定失敗
三、變形
兩個人輪流報數,每次至少報一個,最多報十個,誰能報到100者勝。
對於巴什博弈,那麼我們規定,如果最後取光者輸,那麼又會如何呢?
(n-1)%(m+1)==0則後手勝利
先手會重新決定策略,所以不是簡單的相反行的
例如n=15,m=3
後手 先手 剩餘
0 2 13
1 3 9
2 2 5
3 1 1
1 0 0
先手勝利 輸的人最後必定只抓走一個,如果>1個,則必定會留一個給對手
四、解決方案
1、結論
#include<cstdio> int main() { int n,m; scanf("%d%d",&n,&m); if(n % (m+1) !=0) printf("first win"); else printf("second win"); return 0; }
二、SG定理
#include <bits/stdc++.h>
using namespace std;
const int N = 1000 + 10, INF = 0x3f3f3f3f;
int sg[N], sm[N];
bool vis[N];
void SG(int n, int m)
{
for(int i = 0; i <= n; i++)
{
memset(vis, 0, sizeof vis);
for(int j = max(i-m, 0); j < i; j++) vis[sg[j]] = true;//i的後繼是[max(i-m,0), i-1]
for(int j = 0; j <= n; j++)//mex運算
if(! vis[j])
{
sg[i] = j; break;
}
}
}
int main()
{
int t, n, m;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
SG(n, m);
puts(sg[n] ? "first" : "second");
}
return 0;
}
三、DFS
可以解決,但是TLE!!!
五、例題
http://poj.org/problem?id=2348
http://acm.hdu.edu.cn/showproblem.php?pid=1846
http://acm.hdu.edu.cn/showproblem.php?pid=4764
http://acm.hdu.edu.cn/showproblem.php?pid=1848
六、參考文章
https://www.cnblogs.com/zwfymqz/p/8460192.html
https://blog.csdn.net/luomingjun12315/article/details/45479073