11,848
社区成员
发帖
与我相关
我的任务
分享
--将石子个数想像为三维空间的点(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