poj 1740 一个博弈游戏

题意:对于n堆石子,每堆若干个,两人轮流操作,每次操作分两步,第一步从某堆中去掉至少一个,第二步(可省略)把该堆剩余石子的一部分分给其它的某些堆。最后谁无子可取即输。(参考http://www.cnblogs.com/rainydays/archive/2011/07/09/2101918.html,清晰明白)

思路:首先我们考虑两堆相等的情况,一定是谁取谁输,因为对方永远可以做对称的操作。对于四堆,1、2堆相等,3、4堆相等的情况,一定也是先手输,后手也只需要做对称的操作(在先手取石子的对称堆中取相同多的石子,并把和先手等量的石子分给先手分配给的堆的对称堆。(若先手在3堆取,并分给1堆,那后手就在4堆取,分给2堆)。也就是说对于任意的一对一对相等的情况来说,一定是后手必胜。


我们接下来来证明除上述情况外,所有情况都是先手必胜。因为任何一种情况都可以转化为一对一对相等的情况。若总堆数为奇数的情况,可以把石子最多的一堆的石子分配给其它堆,使得其它堆两两相等。最多一堆的石子绝对是足够多,可以完成这个补齐的任务的。因为我们把石子从小到大排序后画成条形统计图( 这个想法太巧妙了!!)。把相邻两个分成一组(1和2一组,3和4一组……)我们需要用第n堆填补1,3,5……堆我们把需要填补的这些差距(2比1高出的部分,4比3高出的部分……)投影到统计图左侧的y轴上,我们会发现这是一些不连续的区间,其长度总和明显小于第n堆。所以可以补齐。

对于堆数为偶数的情况。我们把最多的一堆削弱到和最少的一堆一样多,并把拿掉的石子分给别的堆,使其一对一对地相等。可行性于前面奇数情况同理。

所以只要判断是不是一对一对的相等的情况即可。

#include <stdio.h>
#include <stdlib.h>
int s[15],n;
int cmp(const void *a,const void *b){
    return (*(int *)a)-(*(int *)b);
}
int main(){
    while(scanf("%d",&n) &&n){
        int i,flag = 1;
        for(i = 0;i<n;i++)
            scanf("%d",&s[i]);
        if((n&1)==0){
            qsort(s,n,sizeof(int),cmp);
            for(i = 0;i<n;i+=2)
                if(s[i] != s[i+1])
                    break;
            if(i == n)
                flag = 0;
        }
        printf("%d\n",flag);
    }
    return 0;
}


你可能感兴趣的:(poj 1740 一个博弈游戏)