2011-08-22 12:14:17Morris

b066. 5. 六芒星棋遊戲:先還是後比較有利?

b066. 5. 六芒星棋遊戲:先還是後比較有利?

內容 :

在一個稱為『六芒星』的星球上,流行著一種 『六芒星棋』的遊戲。這種遊戲是由兩個人來比賽,道具是一個棋盤(如圖一)和13 個鐵圈。遊戲的起始狀態是由兩人互相協調或隨機決定,使用m 個(1 ≤ m ≤ 13)鐵圈在棋盤上圈住 m 個數字。接下來雙方輪流移除棋盤上的鐵圈,每人每次只能移除1 個鐵圈或 2 個相鄰的鐵圈(有直線直接相連的位置視為相鄰),被迫移除最後一個鐵圈的人算輸。

其 實如果仔細思考,可以證明不管起始狀態如何,遊戲中先移除鐵圈的人(先手)與其對手(後手)中必定恰有一人,只要他每次都用對自己最有利的方法來移除鐵 圈,最後一定百分之百得勝。以起始狀態如圖二為例,因為所有鐵圈均不相鄰,故一次只能移除一個鐵圈,先手不管移除哪一個圈,後手只要再移除一個圈,就可以 逼迫先手移除最後一個圈,因此後手有百分之百得勝的把握,我們說成『圖二的起始狀態是後手有利』。若起始狀態如圖三就不同了,如果先手懂得先移除相鄰的兩 個鐵圈(如27 與210),就可以迫使後手去移除最後一個圈,因此先手就有百分之百得勝的把握,我們說成『圖三的起始狀態是先手有利』。
每一種起始狀態,我們用一個整數來表示它,這個整數就是在該起始狀態中所有被鐵圈圈住的數字總和。例如圖二的起始狀態可以用23+25+211=2088 表示,圖三則可用27+29+210=1664 來表示。
請你寫一個程式來判斷在不同的起始狀態下,到底是先手還是後手有利。

 

輸入說明 :

第一行為一個整數n,1 ≤ n ≤ 10,代表接下來的 n 行中每一行有一個以整數表示的起始狀態。

 

輸出說明 :

對每一個輸入的起始狀態,程式必需依順序輸出它們是先手有利(以 1 表示)還是後手有利(以 0 表示)。也就是說,輸出為 n 個 0 或 1 的數字,數字間請用一個空白字元隔開。

 

範例輸入 :

3
32
1024
1664
5
6
13
19
2088
2305

範例輸出 :

0 0 1
1 1 0 0 0

提示 :

出處 :

94全國資訊學科能力決賽



作法 : DP
從最終盤面, 慢慢推回到原始盤面, 原本輸的盤面, 推回去會變成贏的盤面,
然而先手有利, 只限定在百分之百獲勝, 也就是說, 有一個會輸, 就是先手不利,
因此用一個 or 去做運算

/**********************************************************************************/
/*  Problem: b066 "5. 六芒星棋遊戲:先還是後比較有利?" from 94全國資訊學科能力決賽*/
/*  Language: C                                                                   */
/*  Result: AC (6ms, 250KB) on ZeroJudge                                          */
/*  Author: morris1028 at 2011-08-22 12:03:57                                     */
/**********************************************************************************/


#include<stdio.h>
int DP[8192] = {};/*0 win, 1 unsure*/
int LK[13][7] = {
        {2,3,-1},
        {2,5,-1},
        {0,1,3,5,6,-1},
        {0,2,4,6,7,-1},
        {3,7,-1},
        {1,2,6,8,9,-1},
        {2,3,5,7,9,10,-1},
        {3,4,6,10,11,-1},
        {5,9,-1},
        {5,6,8,10,12,-1},
        {6,7,9,11,12,-1},
        {7,10,-1},
        {9,10,-1}
    };
void Build() {
    int a, b, c, tn, t;
    for(a = 1; a <= 8191; a++) {
        tn = a;
        for(b = 0; b < 13; b++) {
            t = tn&(1<<b);
            if(t == 0) {
                t = tn|(1<<b);
                DP[t] |= !DP[tn];
            }
        }
        for(b = 0; b < 13; b++)
            for(c = 0; LK[b][c] >= 0;c++) {
                t = tn&((1<<b)|(1<<LK[b][c]));
                if(t == 0) {
                    t = tn|(1<<b)|(1<<LK[b][c]);
                    DP[t] |= !DP[tn];
                }
            }
    }
}
main() {
    Build();
    int n, x, a;
    while(scanf("%d", &n) == 1) {
        while(n--)
            scanf("%d", &x), printf("%d ", DP[x]);
        puts("");
    }
    return 0;
}