You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prolog斑马问题谓词无限运行,如何修复?

修复Prolog斑马问题代码的关键步骤

核心问题分析

  1. 线索对应混乱:代码中的线索编号完全错位,比如将线索17(40岁在第4位)错误标记为Clue11,遗漏了线索11(第5位演奏drum and bass)和线索12(中间位置在Asgard舞台),直接导致逻辑链断裂。
  2. 命名不匹配:苏格兰人的国籍应为scottish,但代码中写成scott,导致无法匹配问题定义的属性。
  3. 低效位置谓词:原left_of和next_to用append+member实现,会产生大量无效回溯,是程序无限运行的核心原因。
  4. 缺少唯一性约束:仅检查属性存在,未确保每个类别(如国籍、衬衫颜色)的属性在5个DJ中唯一,冗余搜索拖慢运行速度。
  5. 字段顺序不一致:部分线索的DJ字段使用未严格遵循[国籍, 衬衫颜色, 音乐类型, 舞台, 年龄, 爱好]的结构,导致匹配错误。

修复方案

1. 修正基础命名与线索对应

  • 将苏格兰人标识从scott改为scottish,匹配问题中的国籍定义。
  • 重新对应所有线索,确保代码实现与问题描述完全一致,比如补充线索11(第5位演奏drum and bass)、线索12(第3位在Asgard舞台)的代码。

2. 用索引实现高效位置谓词

替换低效的位置判断逻辑,使用1-5的位置索引定义关系,大幅减少回溯:

% 定位DJ在列表中的位置(索引从1开始)
at_position(DJ, Pos, DJs) :- nth1(Pos, DJs, DJ).

% A在B的正左侧(相邻)
immediately_left_of(A, B, DJs) :-
    at_position(A, PosA, DJs),
    at_position(B, PosB, DJs),
    PosB is PosA + 1.

% A在B的左侧某处(不要求相邻)
left_of(A, B, DJs) :-
    at_position(A, PosA, DJs),
    at_position(B, PosB, DJs),
    PosA < PosB.

% A和B相邻
next_to(A, B, DJs) :-
    immediately_left_of(A, B, DJs) ;
    immediately_left_of(B, A, DJs).

3. 提前绑定已知位置的线索

直接将确定位置的属性绑定到DJ列表对应位置,缩小搜索空间:

DJs = [
    DJ1,  % 第1位:30岁(线索3)
    DJ2,
    DJ3,  % 第3位:Asgard舞台(线索12)
    DJ4,  % 第4位:Arcadia舞台(线索2)、40岁(线索17)
    DJ5   % 第5位:drum_and_bass(线索11)
],
DJ1 = [_, _, _, _, 30, _],
DJ3 = [_, _, _, asgard, _, _],
DJ4 = [_, _, _, arcadia, 40, _],
DJ5 = [_, _, drum_and_bass, _, _, _],

4. 添加唯一性约束

确保每个属性类别下的所有值唯一,避免冗余搜索:

% 国籍唯一
maplist(nth1(1), DJs, Nations),
sort(Nations, [american, canadian, dutch, french, scottish]),
% 衬衫颜色唯一
maplist(nth1(2), DJs, Shirts),
sort(Shirts, [black, blue, green, red, white]),
% 音乐类型唯一
maplist(nth1(3), DJs, Genres),
sort(Genres, [drum_and_bass, dubstep, edm, house, trance]),
% 舞台唯一
maplist(nth1(4), DJs, Stages),
sort(Stages, [arcadia, asgard, shangri_la, valhalla, xibalba]),
% 年龄唯一
maplist(nth1(5), DJs, Ages),
sort(Ages, [25, 30, 35, 40, 45]),
% 爱好唯一
maplist(nth1(6), DJs, Hobbies),
sort(Hobbies, [camping, juggling, painting, singing, surfing]),

5. 修正所有线索的实现

严格按照问题描述实现每条线索,比如:

  • 线索10:绿衬衫→绘画→蓝衬衫(连续顺序),用两次immediately_left_of确保位置关系。
  • 线索18:荷兰人→25岁→40岁,结合40岁在第4位,直接绑定25岁和荷兰人的位置。

完整修复代码

% 位置相关谓词,使用索引1-5
at_position(DJ, Pos, DJs) :- nth1(Pos, DJs, DJ).

immediately_left_of(A, B, DJs) :-
    at_position(A, PosA, DJs),
    at_position(B, PosB, DJs),
    PosB is PosA + 1.

left_of(A, B, DJs) :-
    at_position(A, PosA, DJs),
    at_position(B, PosB, DJs),
    PosA < PosB.

next_to(A, B, DJs) :-
    immediately_left_of(A, B, DJs) ;
    immediately_left_of(B, A, DJs).

solve(DJs) :-
    % 定义DJ列表结构,提前绑定已知位置的属性
    DJs = [DJ1, DJ2, DJ3, DJ4, DJ5],
    DJ1 = [_, _, _, _, 30, _],          % 线索3:第1位30岁
    DJ3 = [_, _, _, asgard, _, _],      % 线索12:中间位置(第3位)在Asgard舞台
    DJ4 = [_, _, _, arcadia, 40, _],    % 线索2:第4位在Arcadia;线索17:第4位40岁
    DJ5 = [_, _, drum_and_bass, _, _, _], % 线索11:第5位演奏drum and bass

    % 线索1:苏格兰人在白衬衫DJ左侧某处
    at_position([scottish, _, _, _, _, _], ScottPos, DJs),
    at_position([_, white, _, _, _, _], WhitePos, DJs),
    ScottPos < WhitePos,

    % 线索4:EDM在加拿大人正右侧
    immediately_left_of([canadian, _, _, _, _, _], [_, _, edm, _, _, _], DJs),

    % 线索5:绘画爱好者与dubstep演奏者相邻
    next_to([_, _, _, _, _, painting], [_, _, dubstep, _, _, _], DJs),

    % 线索6:苏格兰人 → 黑衬衫 → dubstep(顺序固定,中间隔黑衬衫)
    immediately_left_of([scottish, _, _, _, _, _], [_, black, _, _, _, _], DJs),
    immediately_left_of([_, black, _, _, _, _], [_, _, dubstep, _, _, _], DJs),

    % 线索7:法国人穿蓝衬衫的DJ相邻
    next_to([french, _, _, _, _, _], [_, blue, _, _, _, _], DJs),

    % 线索8:露营爱好者在队伍两端
    (DJ1 = [_, _, _, _, _, camping] ; DJ5 = [_, _, _, _, _, camping]),

    % 线索9:Asgard舞台的DJ穿蓝衬衫(结合线索12,DJ3穿蓝衬衫)
    DJ3 = [_, blue, _, asgard, _, _],

    % 线索10:绿衬衫 → 绘画 → 蓝衬衫(连续顺序)
    immediately_left_of([_, green, _, _, _, _], [_, _, _, _, _, painting], DJs),
    immediately_left_of([_, _, _, _, _, painting], [_, blue, _, _, _, _], DJs),

    % 线索13:trance与dubstep相邻
    next_to([_, _, trance, _, _, _], [_, _, dubstep, _, _, _], DJs),

    % 线索14:加拿大人在杂耍爱好者正左侧
    immediately_left_of([canadian, _, _, _, _, _], [_, _, _, _, _, juggling], DJs),

    % 线索15:唱歌爱好者在黑衬衫DJ正右侧
    immediately_left_of([_, black, _, _, _, _], [_, _, _, _, _, singing], DJs),

    % 线索16:35岁与杂耍爱好者相邻
    next_to([_, _, _, _, 35, _], [_, _, _, _, _, juggling], DJs),

    % 线索18:荷兰人 → 25岁 → 40岁(顺序固定,40岁在DJ4)
    immediately_left_of([dutch, _, _, _, _, _], [_, _, _, _, 25, _], DJs),
    immediately_left_of([_, _, _, _, 25, _], DJ4, DJs),

    % 线索19:蓝衬衫DJ在Xibalba舞台DJ左侧某处
    left_of([_, blue, _, _, _, _], [_, _, _, xibalba, _, _], DJs),

    % 线索20:冲浪爱好者在Valhalla舞台
    at_position([_, _, _, valhalla, _, surfing], _, DJs),

    % 线索21:穿红衬衫的DJ在法国人右侧某处
    left_of([french, _, _, _, _, _], [_, red, _, _, _, _], DJs),

    % 唯一性约束:所有属性类别下的值唯一
    maplist(nth1(1), DJs, Nations),
    sort(Nations, [american, canadian, dutch, french, scottish]),

    maplist(nth1(2), DJs, Shirts),
    sort(Shirts, [black, blue, green, red, white]),

    maplist(nth1(3), DJs, Genres),
    sort(Genres, [drum_and_bass, dubstep, edm, house, trance]),

    maplist(nth1(4), DJs, Stages),
    sort(Stages, [arcadia, asgard, shangri_la, valhalla, xibalba]),

    maplist(nth1(5), DJs, Ages),
    sort(Ages, [25, 30, 35, 40, 45]),

    maplist(nth1(6), DJs, Hobbies),
    sort(Hobbies, [camping, juggling, painting, singing, surfing]).

% 辅助打印格式化结果
print_solution :-
    solve(DJs),
    nl, write('位置 | 国籍       | 衬衫颜色 | 音乐类型       | 舞台         | 年龄 | 爱好       '), nl,
    write('-----|------------|----------|----------------|--------------|------|------------'), nl,
    print_dj(1, DJs).

print_dj(_, []).
print_dj(Pos, [DJ|Rest]) :-
    DJ = [Nation, Shirt, Genre, Stage, Age, Hobby],
    format('~4d | ~-12w | ~-8w | ~-14w | ~-12w | ~4d | ~-12w~n', [Pos, Nation, Shirt, Genre, Stage, Age, Hobby]),
    NextPos is Pos + 1,
    print_dj(NextPos, Rest).

使用说明

运行print_solution.即可得到格式化的结果,程序不会再无限运行,原因如下:

  • 提前绑定已知位置属性,大幅缩小搜索空间。
  • 索引式位置谓词避免了append带来的无效回溯。
  • 唯一性约束排除了重复属性的无效分支。

内容的提问来源于stack exchange,提问作者guy43535453

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:27:00