zoukankan      html  css  js  c++  java
  • POJ 1704 Georgia and Bob

    前置芝士

    要解决这道题,我们先来了解一下 阶梯博弈

    背景

    \(n\) 个阶梯,地面表示 \(0\) 号阶梯,从下往上编号。每个阶梯都有若干石子,每人每次可以将一个阶梯上的任意个石子移到下一个阶梯。当面临所有石子都位于地面的人输。

    解决方案

    实际上这可以等价于奇数号阶梯的 \(\rm Nim\) 游戏。

    如果对手移动偶数号阶梯的石子,那么我一定可以将它移动的石子移动到下一个偶数号阶梯,这就和奇数号阶梯无关了。而将奇数号阶梯的石子移动到偶数号阶梯,不就相当于取走了石子吗?

    简要题意

    \(\mathtt G\) 和小 \(\mathtt B\) 在玩游戏。给定一个很长的棋盘,每个格子只能放 \(1\) 个棋子,在棋盘上有 \(n\) 个棋子。

    每个人每次必须要向左移动 \(1\) 个棋子,但不能移出棋盘。求先手是否必胜。

    解法

    先考虑 \(n\) 为偶数的情况:将棋子从左到右两两分为一组,若组内棋子之间空格个数异或和为 \(0\) 则必败;反之必胜。

    为啥捏?类似上文的阶梯博弈,我们需要证明组外的空格没有什么用。显然,如果对手移动组内的左棋子,我们跟着移动组内的右棋子是合法的,而且这保证了一个重要的性质 —— 组内空格数不变!故证。

    如果 \(n\) 为奇数,则将第一个单开(实际上是和坐标为 \(0\) 的棋子为一组),剩下还是从左到右两两分为一组。这还是为了保证 “组外空格无用”:左棋子无法移动;且除了第一个棋子自己动,其它的变化不会影响组内空格数。

    代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int T, n, a[1002], ans;
    
    int read() {
    	int x = 0, f = 1; char s;
    	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
    	while(s >= '0' && s <= '9') {
    		x = (x << 1) + (x << 3) + (s ^ 48);
    		s = getchar();
    	}
    	return x * f;
    }
    
    int main() {
    	T = read();
    	while(T --) {
    		ans = 0;                                                                                                                                                                                 
    		n = read();
    		for(int i = 1; i <= n; ++ i) a[i] = read();
    		sort(a + 1, a + n + 1);
    		for(int i = 1; i <= n; i += 2) ans ^= a[n - i + 1] - a[n - i] - 1;
    		puts(ans ? "Georgia will win" : "Bob will win");
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据库设计>相片管理设计思路小讨论
    ADO.NET数据库连接的几种方式
    ADO.NET两种事务处理方法
    ADO.NET调用存储过程
    [sql server] 得到连续日期查询(转)
    数据库设计基础>范式
    repeater控件的事件
    小偷程序的学习总结
    《道德经》程序员版第十章
    数据库设计基础>ER图(转)
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12330234.html
Copyright © 2011-2022 走看看