Hdu Stone Game ( 博弈论 )

题目: 有三堆石子,两个人轮流做这样的操作,将三堆石子中的一对扔掉,从剩下的两堆中,选一堆并将其分成两堆,最后不能操作的人胜

Sample Input

5
1 1 1
2 2 2
5 6 7
4 2 2
12 28 4

要注意,偶数只能拆成两个奇数或者两个偶数;一个奇数只能拆成一个奇数和一个偶数 
由于1 1 1是一个必输态,面对1 1 1的人一定是输的那个,而对于三个奇数的状态来讲,面对这种情况
的人只能将三个奇数扔出一个,然后剩下的两个数拆为:奇数,奇数,偶数

对于任何的“奇数,奇数,偶数”,都可以再被操作回“奇数,奇数,奇数”,具体方法就是扔掉一个奇数,然后把偶数拆为连个奇数。由于一直都在数一直都是在减少,如果第一个人面对的是三个奇数的状态,它只能将它转化为“两奇一偶”的状态,别无选择,第二个人就可以将“两奇一偶”的状态转化为三个奇数的状态,而且在拆分之后,三队石子都不能为空,很显然,第二个人总会拆掉1 1 1的状态,那么第一个人面对1 1 1的状态就是输了。用T表示三个奇数的状态,用S表示两奇一偶的状态,转化过程如下

一   二    一    二               二     一 ( 一代表走第一步的人,二代表第二个走的人)

T -> S -> T -> S -> ……-> S -> T(1 1 1);

因此,对第一个人来讲,奇数,奇数,奇数是必输的


有上所述,面对两奇一偶的人一定是赢家,那么两偶一奇呢? 很简单,扔掉一个偶数,将两一个偶数拆成两个奇数,就变成了三个奇数,将必败态留给对手了

因此,对于第一个人来讲,三个数的奇偶性不完全相同,是必胜的


接下来讨论三个偶数。对于三个偶数,扔掉的肯定是一个偶数,那么一定是剩下了两个偶数,所以,“扔”这一步是没有选择的,一定是偶数;那么在拆的过程中就不一样了,拆可能拆为两奇一偶和三个偶,而两奇一偶,由上可知,那么对方必胜,因此只能拆为三个偶数, 当无法拆违三个偶数的时候,就输了。对最小的三个偶数2 2 2,面对2 2 2的人一定输,显而易见,所以,最坏的可能就是就要看是谁会面对2 2 2的状态了。那么2 2 2 的状态是2的因子都相等,那么只要每次变换,都使得2的因子都相等,就会使得对手在最后面对到2 2 2的状态了(因为保证了2的因子相等,而且一直在减小),那么怎么拆呢?设三个数为 k1*2^x1, k2*2^x2, k3*2^x3, 其中,k1,k2,k3都是奇数。假设x1 < x2, 那么k2*2^x2 = k2*2^(x2-x1)*2^x1 = k2 * ( m1 + m2 )*2^x1, 也就是说,将2因子多的那堆拆成m1*2^x1和m2*2^x2,其中m1,m2和k2都是奇数,拆完之后,三个2的因子数都是x1.

由此可知,任何2因子不完全相等的三个数是可以拆成相等的三个数,那么总会拆到2 2 2,那么也就是说都相等是必败态,不全相等时必胜

代码:

#include 

int n;
int a, b, c;
int na, nb, nc;
bool isa, isb, isc;

int main()
{
    scanf("%d", &n);
    while ( n-- ) {
        scanf("%d%d%d", &a, &b, &c);
        isa = isb = isc = 0;
        if ( a%2 ) isa = 1;
        if ( b%2 ) isb = 1;
        if ( c%2 ) isc = 1;
        if ( isa && isb && isc ) printf("YES\n");
        else if ( ( isa || isb || isc ) ) printf("NO\n");
        else {
            na = nb = nc = 0;
            while ( a % 2 == 0 ) na ++, a /= 2;
            while ( b % 2 == 0 ) nb ++, b /= 2;
            while ( c % 2 == 0 ) nc ++, c /= 2;
            if ( na == nb && nb == nc ) printf("YES\n");
            else printf("NO\n");
        }
    }
}
        


你可能感兴趣的:(博弈论)