1. 程式人生 > >【POJ】1740.A New Stone Game

【POJ】1740.A New Stone Game

eof pac 博弈 turn += 多余 stream ring 就是

題解

想去學習一下博弈論的SG函數
不過貌似這道題就是猜結論並且證明

題意是,隨便選擇一堆石子,扔掉至少一個,然後從扔石子的這堆裏選擇任意多(可以不選)放到其他任意多的未選擇完的石堆裏
一堆石子,先手必勝
兩堆石子,如果兩堆石子相同,那麽後手必勝,先手一定會使兩堆不同,那麽後手把兩堆恢復相同,最後先手的局面就是(1,1),此時後手必勝
如果兩堆石子不同,先手必勝,因為先手讓兩堆石子相同即可
三堆石子,先手必勝,先手也可以讓兩堆石子相同
四堆石子,由於三堆必勝,那麽只有局面1 1 1 1的時候,此時後手必勝,先手不得不扔走一個,那麽猜測一下,只有偶數堆石子並且石子兩兩相等可以配對的時候,後手必勝

然後證明一下這個結論

我們認為,必敗態是,石子堆為偶數,且石子堆每一堆可以和另一堆相等的石子堆形成配對的時候,先手必敗

必勝態必勝(即必勝態可以轉化到一個必敗態)
奇數堆石子時,先手挑選石子堆最多的那一堆,扔掉至少一個,我們將剩下的偶數個數從小到大排序,差分不會超過石子堆最多的那一堆數量-1,然後我們使剩余石子堆形成必敗態,扔掉多余的石子
偶數堆石子且至少有一個不配對的時候,刪掉配對的部分,那麽剩下的偶數個石堆從小到大排序,令石子數最多的堆先扔掉一個,和石子數最少的匹配,那麽我們還可以分配,最大 - 最小 - 1個石子,由於第二大的石堆和第一大的石堆不匹配,至少相差1,那麽剩余的石子按照差分可以給剩下的石堆分配石子,多余的扔掉

必敗態必敗(即必敗態不能走到一個必敗態)
扔掉一個石子一定會出現兩堆不同

代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
//#define ivorysi
#define MAXN 105
#define eps 1e-8
using namespace std;
typedef long long int64;
typedef double db;
int N;
int a[105];
void Solve() {
    for(int
i = 1 ; i <= N ; ++i) { scanf("%d",&a[i]); } sort(a + 1,a + N + 1); if(N & 1) {puts("1");return;} for(int i = 1 ; i <= N ; i += 2) { if(a[i] != a[i + 1]) {puts("1");return;} } puts("0"); } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif while(scanf("%d",&N) != EOF && N) { Solve(); } }

【POJ】1740.A New Stone Game