Play with SQL (Mission 3)

feilniu 2010-08-18 11:31:56
这是一些有趣的小问题。我们可以尝试用T-SQL来解答。
Just for fun!

大家回复时,别忘了贴出自己的代码,可以共同分享一下SQL的技巧和思维的火花。


问题:
有3堆石子,石子个数分别为a,b,c。(简化起见,取a,b,c在1到9之间。更大的数字规律也是相同的。)
你和对手轮流拿取。一次可以拿1到任意多个,但只能在其中一堆拿。
拿到最后一个石子的一方获胜。
请问如何才能必胜。
例如:现在三堆石子的个数分别是7,8,9,你应该选择先拿还是后拿?怎么拿?

*扩展:更一般地,将问题改为N堆石子,会有什么规律?
...全文
202 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
keer019 2010-08-26
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 SQLCenter 的回复:]789拿8不行,导致对方变成偶数,失败。[/Quote]
SQLCenter 2010-08-20
  • 打赏
  • 举报
回复
789拿8不行,导致对方变成偶数,失败。
SQLCenter 2010-08-20
  • 打赏
  • 举报
回复
推导可能有误,未验证,轻喷。
SQLCenter 2010-08-20
  • 打赏
  • 举报
回复
7,8,9
-------
拿奇数堆就剩1粒,那8就全拿都是必赢得。

防止出现1,1,1,N,这种对手拿走N-1,成为对手必赢的态势。
feilniu 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 playwarcraft 的回复:]

我推了一下,貌似7,8,9三堆的话,先拿的一定赢
从7那堆拿走6个就赢了
[/Quote]

19楼同学的心算能力实在了得!
SQLCenter 2010-08-20
  • 打赏
  • 举报
回复
有时候电脑可能不如人脑:

1、先手
2、剩下的石头总数是偶数,并且只有1粒石子的堆数为奇数堆。

不知道对不
playwarcraft 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 feilniu 的回复:]
以下是我的解法,本质上就是穷举:

SQL code

--将石子个数想像为三维空间的点(a,b,c)
--一次拿取相当于是从一个点(a,b,c)移动到另一个点(a-i,b,c)或(a,b-i,c)或(a,b,c-i),其中i为正整数,且不会使a-i或b-i或c-i出现负数。
--当轮到一方时,该方会胜利的点称为胜点,反之称为败点
CREATE TABLE Points3D(
……
[/Quote]

赞一个
playwarcraft 2010-08-20
  • 打赏
  • 举报
回复
我推了一下,貌似7,8,9三堆的话,先拿的一定赢
从7那堆拿走6个就赢了
feilniu 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 realgz 的回复:]

最优答案的解法不知道怎么和4gl的优势挂钩上去……
[/Quote]

SQL是基于集合的说明式语言。比如在17楼例子中,只需要说明满足什么条件的点是胜点或败点,而不需要关心如何去计算这些点。如果是过程式语言,那只能是一个个Foreach去遍历了。
feilniu 2010-08-20
  • 打赏
  • 举报
回复
以下是我的解法,本质上就是穷举:

--将石子个数想像为三维空间的点(a,b,c)
--一次拿取相当于是从一个点(a,b,c)移动到另一个点(a-i,b,c)或(a,b-i,c)或(a,b,c-i),其中i为正整数,且不会使a-i或b-i或c-i出现负数。
--当轮到一方时,该方会胜利的点称为胜点,反之称为败点
CREATE TABLE Points3D(
a int NOT NULL,
b int NOT NULL,
c int NOT NULL,
is_fail bit NULL, --是否败点
PRIMARY KEY CLUSTERED(a, b, c));
--初始化解空间
WITH N10 AS(SELECT n = n - 1 FROM dbo.Nums WHERE n <= 10)
INSERT INTO Points3D
SELECT
a = a.n,
b = b.n,
c = c.n,
is_fail = NULL
FROM N10 a
CROSS JOIN N10 b
CROSS JOIN N10 c
ORDER BY a, b, c;
--(0,0,0)是败点
UPDATE Points3D SET is_fail = 1 WHERE a = 0 AND b = 0 AND c = 0
--穷举
WHILE 1 = 1
BEGIN
--以下表别名:pf指point_from,起点;pt指point_to,终点

--一次可以移动到败点的点为胜点
UPDATE pf SET is_fail = 0
--SELECT *
FROM Points3D pf
INNER JOIN Points3D pt
ON pf.is_fail IS NULL
AND pt.is_fail = 1
AND ((pf.a > pt.a AND pf.b = pt.b AND pf.c = pt.c)
OR (pf.a = pt.a AND pf.b > pt.b AND pf.c = pt.c)
OR (pf.a = pt.a AND pf.b = pt.b AND pf.c > pt.c))

--一次只能移动到胜点的点为败点
UPDATE pf SET is_fail = 1
--SELECT *
FROM Points3D pf
INNER JOIN (
SELECT pf.a, pf.b, pf.c,
pt_all = COUNT(1),
pt_suc = COUNT(CASE WHEN pt.is_fail = 0 THEN 1 END)
FROM Points3D pf
INNER JOIN Points3D pt
ON pf.is_fail IS NULL
AND ((pf.a > pt.a AND pf.b = pt.b AND pf.c = pt.c)
OR (pf.a = pt.a AND pf.b > pt.b AND pf.c = pt.c)
OR (pf.a = pt.a AND pf.b = pt.b AND pf.c > pt.c))
GROUP BY pf.a, pf.b, pf.c
HAVING COUNT(1) = COUNT(CASE WHEN pt.is_fail = 0 THEN 1 END)
) pt_suc
ON pf.a = pt_suc.a AND pf.b = pt_suc.b AND pf.c = pt_suc.c

--计算结束后退出循环
IF @@ROWCOUNT = 0 BREAK
END

--所有败点:只要保证轮到对方时石子个数为如下值,则必胜
SELECT a, b, c FROM Points3D WHERE a <= b AND b <= c AND is_fail = 1
realgz 2010-08-20
  • 打赏
  • 举报
回复
最优答案的解法不知道怎么和4gl的优势挂钩上去……
htl258_Tony 2010-08-20
  • 打赏
  • 举报
回复
UP。
realgz 2010-08-20
  • 打赏
  • 举报
回复
因为我google了,然后然后思路完全被google出来的结果左右了。。。。。。。。。。下次不敢了,先老老实实做题
realgz 2010-08-20
  • 打赏
  • 举报
回复
然后 还能只能 a^b^c=0 时 没有拿法能使得 a1^b2^c2=0 ,但是a^b^c<>0时一定能 a1^b2^c2=0,更万恶的是根据以上推论能得出一个公式计算应该拿多少个。
realgz 2010-08-20
  • 打赏
  • 举报
回复
因为我找到一个公式 a^b^c=0 时赢……
  • 打赏
  • 举报
回复
re, 用程序我还没想起来怎么写, 更别说sql了。
王向飞 2010-08-18
  • 打赏
  • 举报
回复
obuntu 2010-08-18
  • 打赏
  • 举报
回复

路过。。
claro 2010-08-18
  • 打赏
  • 举报
回复
看来除了感性和理性我没有,智力我也很低。
realgz 2010-08-18
  • 打赏
  • 举报
回复
因为有个顺序问题,无法进行集合运算。纯sql没想出来。再想想。
加载更多回复(10)

11,848

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 非技术版
社区管理员
  • 非技术版社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧