如何用Clingo的1{...}1规则实现数独的宫约束?
用Clingo的1{...}1基数约束实现数独宫约束
可以用1{...}1的基数约束规则实现数独的宫约束,你之前的代码未生效是因为整数除法使用错误、未定义对应谓词以及变量绑定逻辑问题,以下是修正后的实现方案:
问题分析
你之前尝试的宫约束代码存在三个核心问题:
- Clingo中整数除法需用
//,而非/(/是浮点除法,会导致宫编号计算为非整数,无法正确分组); - 未定义
subgrid/1谓词,导致筛选条件subgrid(...)永远不成立; - 宫编号的计算逻辑和变量
S的绑定顺序有误,无法正确关联宫的范围。
正确实现方案(两种写法)
写法1:先定义格子所属宫,再用基数约束
这种写法和你原有的行、列约束逻辑风格统一,先明确每个单元格对应的宫,再约束每个宫内数字唯一:
subgrid_size(3). number(1..S*S) :- subgrid_size(S). sudoku(X,Y,N) :- initial(X,Y,N). % 基础约束:每个单元格有且仅有一个数字 1{sudoku(X,Y,N): number(N)}1 :- number(X), number(Y). % 行约束:每行每个数字仅出现一次 1{sudoku(X,Y,N): number(X)}1 :- number(N), number(Y). % 列约束:每列每个数字仅出现一次 1{sudoku(X,Y,N): number(Y)}1 :- number(X), number(N). % 定义每个(X,Y)对应的宫G(使用整数除法//) cell_in_grid(X,Y,G,S) :- subgrid_size(S), number(X), number(Y), G = ((X-1)//S)*S + ((Y-1)//S) + 1. % 宫约束:每个宫G内,每个数字N仅出现一次 1{sudoku(X,Y,N): cell_in_grid(X,Y,G,S)}1 :- subgrid_size(S), number(N), number(G).
写法2:直接在基数约束中计算宫范围
无需额外定义cell_in_grid谓词,直接在基数约束的筛选条件里计算宫的X/Y边界:
subgrid_size(3). number(1..S*S) :- subgrid_size(S). sudoku(X,Y,N) :- initial(X,Y,N). % 基础约束 1{sudoku(X,Y,N): number(N)}1 :- number(X), number(Y). 1{sudoku(X,Y,N): number(X)}1 :- number(N), number(Y). 1{sudoku(X,Y,N): number(Y)}1 :- number(X), number(N). % 宫约束:直接计算宫G对应的X/Y范围,约束每个数字N在宫内唯一 1{sudoku(X,Y,N): subgrid_size(S), X >= ((G-1)//S)*S + 1, X <= ((G-1)//S)*S + S, Y >= ((G-1)%S)*S + 1, Y <= ((G-1)%S)*S + S }1 :- subgrid_size(S), number(N), number(G).
两种方案的优势
和你找到的禁止约束方案相比,用1{...}1基数约束的写法:
- 逻辑上和行、列约束完全统一,代码风格更一致;
- 直接通过正向约束定义合法状态,而非禁止非法状态,更符合ASP的声明式编程思路。
内容的提问来源于stack exchange,提问作者xarxax
相关产品推荐
相关产品推荐

