HDU 2177 取(2堆)石子游戏 (威佐夫博奕)

本文提供了一道经典博弈论问题的解题思路及代码实现,重点介绍了如何通过数学方法判断并找到最优解,即玩家首次取石子的最佳数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2177


题意:不光求出胜负,还要求出胜利的话第一次可以怎么取。


先考虑两边同时取的情况,差值不变,根据差值计算出取完后两堆中较小的值,若这个计算出的值比没取之前的较小值小则可以取,然后加上差值就是取完后较大的堆的值。
如果在一堆中取,则只需取较大的那堆即可,至于为什么我还没想好怎么解释.....然后枚举取的数量进行判断即可。


#include <iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int main() {
	int n, m;
	while(~scanf("%d %d", &n, &m) , m + n) {
		if(n > m) {
			swap(n, m);  
		}
		int k = m - n;
		int tmp = (1.0 * k * (sqrt(5) + 1) / 2);
		if(tmp == n) puts("0");
		else if(tmp < n) {  //可以两堆同时取的情况 
			puts("1");
			printf("%d %d\n", tmp, m - (n - tmp));
			int i;
			for(i = 1; i <= m; i++) {  //枚举取的数量,判断是否为奇异局势 
				k--;
				if(k < 0) {  //注意k正负的处理 
					tmp = (1.0 * (-k) * (sqrt(5) + 1) / 2);
					if(m - i == tmp) {  //此时m - i成为了较小堆 
						printf("%d %d\n", m - i, n);
					}
				}
				else {
					tmp = (1.0 * k * (sqrt(5) + 1) / 2);
					if(tmp == n) {
						printf("%d %d\n", n, m - i);
					}
				}
			}
		}
		else {  //此时只能从较大堆取 
			puts("1");
			int i;
			for(i = 1; i <= m; i++) {
				k--;
				tmp = (1.0 * k * (sqrt(5) + 1) / 2);
				if(tmp == n) {
					printf("%d %d\n", n, m - i);
				}
			}
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值