HDOJ4315[阶梯博弈]

来源:互联网 发布:脸型测试软件 在线 编辑:程序博客网 时间:2024/05/01 23:46

题目: 题目链接

Problem Description
Alice and Bob are playing a game called "Climbing the Hill". The game board consists of cells arranged vertically, as the figure below, while the top cell indicates the top of hill. There are several persons at different cells, and there is one special people, that is, the king. Two persons can't occupy the same cell, except the hilltop.

At one move, the player can choose any person, who is not at the hilltop, to climb up any number of cells. But the person can't jump over another one which is
above him. Alice and Bob move the persons alternatively, and the player who move the king to the hilltop will win. 


Alice always move first. Assume they play optimally. Who will win the game?
 
Input
There are several test cases. The first line of each test case contains two integers N and k (1 <= N <= 1000, 1 <= k <= N), indicating that there are N persons on the
hill, and the king is the k-th nearest to the top. N different positive integers followed in the second line, indicating the positions of all persons. (The hilltop is No.0 cell, the cell below is No.1, and so on.) These N integers are ordered increasingly, more than 0 and less than 100000.
 
Output
If Alice can win, output "Alice". If not, output "Bob".
 
Sample Input
3 31 2 42 1100 200
 
Sample Output
BobAlice
题目大意就是说:两个人挪动棋子,棋子可以向上移动,但不能跨越前面的棋子,最先把king移到山顶的人获胜,给出棋子数和king距山顶的次序,第二行给出每个棋子的位置。求出先获胜的人。

题解:

分析:
 1、n 为偶数时:问题简化一下,假设全都是黄球,谁把最后一个球移出谁就赢
(a1,a2) (a3,a4)  …… ( a(2*n-1) , a(2*n) ) ……(a(n-1),an)其中第 i 个球与第 i+1 个球是相邻的,i 为基数,谁面对这个状态谁就必输。
理由很简单,先手移动第 i 个球,后手移动第 i+1 个球,使之仍然保持必赢状态。
回到原问题谁先移出红球谁就赢,假设红球不是第一个球(因为第一个球Alice直接就赢了)
很显然如果红球在偶数位置后手必赢,如果在基数 i 位置,则只需将 第 i-1 个球移到第一个位置就ok了。
所以与红球位置无关。至于产生这个状态(a1,a2) (a3,a4)  …… ( a(2*n-1) , a(2*n) ) ……(a(n-1),an),那么就是简单的 Nim问题了
2、n 为基数时:假设红球是第1、2个球。(a1) (a2,a3)(a4,a5)…… (a(2*n),a(2*n+1)) …… (a(n-1),an) 谁面对这个状态必赢!理由是先手直接把 a1 取走然后就变成上面的情况了,
如果红球在第 2 个位置那么就是必输状态。

这样就分情况来判断,上代码:
#include <iostream>#include <cstdio>#include <string>#include <string.h>#include <map>#include <vector>#include <cstdlib>#include <cmath>#include <algorithm>#include <cmath>#include <queue>#include <set>#include <stack>using namespace std;int min(int a, int b){    if(a<=b)        return a;    return b;}int max(int a, int b){    if(a>=b)        return a;    return b;}double min(double a, double b){    if(a<=b)        return a;    return b;}double max(double a, double b){    if(a>=b)        return a;    return b;}#define N 1010int a[N];int main(){    int n, k;    int tmp;    while(scanf("%d%d", &n, &k) != EOF)    {        a[0] = -1;        int tp = 0;        for(int i = 1; i <= n; ++i)            scanf("%d", &a[i]);        if(k==1)        {            printf("Alice\n");            continue;        }        for(int i = n; i > 0; i -= 2)            tp ^= (tmp = a[i] - a[i-1] -1);//建立Nim堆        if(n%2==1 && k==2)            tp = tp ^ (tmp-1)^tmp;        if(tp==0)            puts("Bob");        else            puts("Alice");    }    return 0;}
努力努力.....
一些附加的解说:
阶梯博弈:http://blog.csdn.net/longshuai0821/article/details/7793043
http://blog.csdn.net/julyana_lin/article/details/8084752