OptaPlanner笔记6 N皇后

N 个皇后

问题描述

将n个皇后放在n大小的棋盘上,没有两个皇后可以互相攻击。 最常见的 n 个皇后谜题是八个皇后谜题,n = 8:

约束:

  • 使用 n 列和 n 行的棋盘。
  • 在棋盘上放置n个皇后。
  • 没有两个女王可以互相攻击。女王可以攻击同一水平线、垂直线或对角线上的任何其他女王。

求解结果(time limit 5s)

问题大小

n 搜索空间
4 256
8 10^7
16 10^19
32 10^48
64 10^115
256 10^616

域模型

java 复制代码
@Data
@AllArgsConstructor
public class Column {
    private int index;
}
@Data
@AllArgsConstructor
public class Row {
    private int index;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@PlanningEntity
public class Queen {
    @PlanningId
    private Integer id;
    @PlanningVariable
    private Column column;
    @PlanningVariable
    private Row row;
    // 升序对角线索引(左上到右下)
    public int getAscendingDiagonalIndex() {
        return column.getIndex() + row.getIndex();
    }
    // 降序对角线索引(左下到右上)
    public int getDescendingDiagonalIndex() {
        return column.getIndex() - row.getIndex();
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@PlanningSolution
public class NQueen {
    @ValueRangeProvider
    @ProblemFactCollectionProperty
    private List<Column> columnList;
    @ValueRangeProvider
    @ProblemFactCollectionProperty
    private List<Row> rowList;
    @PlanningEntityCollectionProperty
    private List<Queen> queenList;
    @PlanningScore
    private HardSoftScore score;
}

例如:

Queen Column Row AscendingDiagonalIndex DescendingDiagonalIndex
A1 0 1 1 (**) -1
B0 1 0 (*) 1 (**) 1
C2 2 2 4 0
D0 3 0 (*) 3 3

(*)(**)的皇后可以互相攻击

求解器(约束提供者)

java 复制代码
public class NQueenConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
        		// 列冲突
                columnConflict(constraintFactory),
                // 行冲突
                rowConflict(constraintFactory),
                // 升序对角线冲突
                ascendingDiagonalIndexConflict(constraintFactory),
                // 降序对角线冲突
                descendingDiagonalIndexConflict(constraintFactory),
        };
    }

    public Constraint columnConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                .forEach(Queen.class)
                .join(Queen.class,
                        Joiners.equal(Queen::getColumn),
                        Joiners.lessThan(Queen::getId))
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("Column conflict");
    }

    public Constraint rowConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                .forEach(Queen.class)
                .join(Queen.class,
                        Joiners.equal(Queen::getRow),
                        Joiners.lessThan(Queen::getId))
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("Row conflict");
    }

    public Constraint ascendingDiagonalIndexConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                .forEach(Queen.class)
                .join(Queen.class,
                        Joiners.equal(Queen::getAscendingDiagonalIndex),
                        Joiners.lessThan(Queen::getId))
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("AscendingDiagonalIndex conflict");
    }

    public Constraint descendingDiagonalIndexConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                .forEach(Queen.class)
                .join(Queen.class,
                        Joiners.equal(Queen::getDescendingDiagonalIndex),
                        Joiners.lessThan(Queen::getId))
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("DescendingDiagonalIndex conflict");
    }
}

应用

java 复制代码
public class NQueenApp {
    public static void main(String[] args) {
        SolverFactory<NQueen> solverFactory = SolverFactory.create(new SolverConfig()
                .withSolutionClass(NQueen.class)
                .withEntityClasses(Queen.class)
                .withConstraintProviderClass(NQueenConstraintProvider.class)
                .withTerminationSpentLimit(Duration.ofSeconds(5)));
        NQueen problem = generateDemoData();
        Solver<NQueen> solver = solverFactory.buildSolver();
        NQueen solution = solver.solve(problem);
        printTimetable(solution);
    }

    public static NQueen generateDemoData() {
        List<Column> columnList = new ArrayList<>();
        List<Row> rowList = new ArrayList<>();
        List<Queen> queenList = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            columnList.add(new Column(i));
            rowList.add(new Row(i));
            queenList.add(new Queen(i, null, null));
        }
        return new NQueen(columnList, rowList, queenList, null);
    }

    private static void printTimetable(NQueen nQueen) {
        System.out.println("");
        List<Column> columnList = nQueen.getColumnList();
        List<Row> rowList = nQueen.getRowList();
        List<Queen> queenList = nQueen.getQueenList();
        Map<Column, Map<Row, List<Queen>>> queenMap = queenList.stream()
                .filter(queen -> queen.getColumn() != null && queen.getRow() != null)
                .collect(Collectors.groupingBy(Queen::getColumn, Collectors.groupingBy(Queen::getRow)));
        System.out.println("|     | " + columnList.stream()
                .map(room -> String.format("%-3s", room.getIndex())).collect(Collectors.joining(" | ")) + " |");
        System.out.println("|" + "-----|".repeat(columnList.size() + 1));
        for (Column column : columnList) {
            List<List<Queen>> cellList = rowList.stream()
                    .map(row -> {
                        Map<Row, List<Queen>> byRowMap = queenMap.get(column);
                        if (byRowMap == null) {
                            return Collections.<Queen>emptyList();
                        }
                        List<Queen> cellQueenList = byRowMap.get(row);
                        if (cellQueenList == null) {
                            return Collections.<Queen>emptyList();
                        }
                        return cellQueenList;
                    })
                    .collect(Collectors.toList());

            System.out.println("| " + String.format("%-3s", column.getIndex()) + " | "
                    + cellList.stream().map(cellQueenList -> String.format("%-3s",
                            cellQueenList.stream().map(queen -> queen.getId().toString()).collect(Collectors.joining(", "))))
                    .collect(Collectors.joining(" | "))
                    + " |");
            System.out.println("|" + "-----|".repeat(columnList.size() + 1));
        }
        List<Queen> unassignedQueens = queenList.stream()
                .filter(Queen -> Queen.getColumn() == null || Queen.getRow() == null)
                .collect(Collectors.toList());
        if (!unassignedQueens.isEmpty()) {
            System.out.println("");
            System.out.println("Unassigned Queens");
            for (Queen Queen : unassignedQueens) {
                System.out.println("  " + Queen.getColumn() + " - " + Queen.getRow());
            }
        }
    }
}
相关推荐
青少儿编程课堂2 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
在所不辞兄2 小时前
为什么在新能源汽车电驱与热管理开发中,AI驱动的数字孪生和数据驱动仿真正在部分替代对物理台架与实车标定的依赖?
人工智能·深度学习·神经网络·算法·机器学习
I_belong_to_jesus13 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Code_Solitude20 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司20 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP1 天前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
思麟呀1 天前
背包DP(01背包+完全背包)
c++·算法
笑容掩饰我的失落1 天前
区块链从小白到精通(七):Solidity 语法精讲——数据类型、函数、修饰器与事件
算法·区块链·php·智能合约·哈希算法
Pniubi1 天前
力扣24. 两两交换链表中的节点(递归)
算法·leetcode·链表