POJ 1740 A New Stone Game【博弈】

题目链接:

http://poj.org/problem?id=1740

题意:

n 堆棋子,每次可以从一堆中拿出任意多个任意分配到其他非0的堆中,谁没有棋子可拿谁输,问先手是否赢。

分析:

好智障啊,题意就没搞清楚,一直以为是拿出来的只能放到一个非0堆中,其实是随意放在任何非0堆中!这很关键!
博弈的关键做出对称状态后再完全模仿对手
后手如果有条件完全模仿先手的状态,那么后手一定会赢。
如果堆数为偶数,我们分析如何会出现对称状态,如果本身就是对称的状态,如a,a,b,b,c,c...,后手完全模仿先手的操作,那么后手必赢。否则,先手可以来制造对称状态,即先手可以将最大的一堆中的石子平分给其他堆使得堆中棋子两两相等,面对对称状态,此时先手变为了后手,必赢。
如果堆数为奇数,从最大堆中拿出一部分,填补剩下的所有堆,使得两两相等。剩下的拿走。先手必赢。
那么问题来了,将最大的一堆中的石子平分给其他堆使得堆中棋子数两两相等,这个一定可以实现么?
首先所有堆按照棋子个数排个序,则有 an=a0+(a1a0)+(a2a1)+...(anan1) ,那么两两一组,组内元素之差的累加和一定小等于最大堆比最小堆多的数目。偶数堆石子之和为偶数,有这两个条件,便可以保证可以实现堆中元素两两相等了。

代码:


/*************************************************************************
    > File Name: 1740.cpp
    > Author: jiangyuzhu
    > Mail: 834138558@qq.com 
    > Created Time: 2016/7/30 11:27:53
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 10 + 5;
int a[maxn];
int main (void)
{
    int n;
    while(scanf("%d", &n) && n){
        bool flag = true;
        for(int i = 0; i < n; i++){
            scanf("%d", &a[i]);
        }
        if(n & 1) puts("1");
        else{
            sort(a, a + n);
            for(int i = 0; i < n; i += 2){
                if(a[i] != a[i + 1]){
                    puts("1");
                    flag = false;
                    break;
                }
            }
            if(flag) puts("0");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值