有人可以解释这个n-queens代码在做什么吗?

时间:2017-04-26 21:41:11

标签: java n-queens

我们被要求在课堂上做n-queens问题,我在网上遇到了这段代码。我们提交的截止日期已经过去了,我提出了一个使用数组的解决方案,但是这段代码对我感兴趣,因为它比我的解决方案所需的行少得多。我不太确定else语句中发生了什么,所以如果有人能够解释,我将非常感激!提前谢谢!

import java.util.Scanner;

public class NQueens {

private static int size;    //n
private static int mask;    //
private static int count;   //solutions

//Uses recursion to calculate the number of possible solutions, and increments "count".
public static void backtrack(int y, int left, int down, int right) {

    int bitmap;
    int bit;

    if (y == size) {
        count++;
    }
    else {
        bitmap = mask & ~(left | down | right);
        while (bitmap != 0) {
            bit = -bitmap & bitmap;
            bitmap ^= bit;
            backtrack(y + 1, (left | bit) << 1, down | bit, (right | bit) >> 1);
        }
    }
}

//main
public static void main(String[] args) {
    Scanner keyboard = new Scanner(System.in);
    System.out.print("Enter the number of queens: ");
    size = keyboard.nextInt();
    count = 0;
    mask = (1 << size) - 1;
    backtrack(0, 0, 0, 0);
    System.out.println("The valid number of arrangements is " + count);
    }
}

1 个答案:

答案 0 :(得分:2)

我会用松散的术语在这里给出详细信息的路标。

  • 整体方法是什么?

正如方法名称提示,backtrack实现了对解决方案的“回溯”搜索。 https://en.wikipedia.org/wiki/Backtracking这意味着它驱逐每条可能的路径,决定每个分支是否仍然可以执行任务,在被证明不可行的瞬间放弃任何路径,并回溯到最近的决策点尝试另一条路。引用维基百科关于N皇后问题的文章,“在常见的回溯方法中,部分候选人是董事会的第一k行中k个皇后的排列,所有行都在不同的行和列中 [和diagonals -Ed。] 。任何包含两个相互攻击的皇后的部分解决方案都可以放弃。“

“部分候选人”是指从k == 0开始的每个女王的一系列展示位置(无论下一个选择是什么,解决方案仍然可行),然后是1(因为某些选择可能的解决方案更少)将女王置于攻击位置),然后2,依此类推,直至N。对于每个放置,您将女王放在一个新行中,因为显然任何前一行都不是一个可行的选择。

  • 算法中的“展示位置”是什么?

要在N x N棋盘中模拟女王的位置,您需要一个数据结构来表示该棋盘,以及是否占用了一个正方形,以及两个占用的正方形是否在相互攻击关系。

示例中的数据结构是位图。这是它变得棘手的地方。你需要熟悉位操作才能遵循它。

private static int size;    //n
private static int mask;
private static int count;   //solutions

size是皇后的数量,等于占用的行数。 count是找到的解决方案的数量 masksize个连续1位的序列,用于屏蔽int个值到问题的大小。在八皇后示例中,它将等于0xff0b1111_1111

backtrack(int y, int left, int down, int right)

y很容易,它是到目前为止放置的当前皇后数,相当于目前为止拥有皇后的行数。其他三个值使用位操作技巧来揭示是否存在可在三个方向上计算的攻击向量。这是它变得模糊的地方。我没有完成任务,但我会说明如何进行全面了解。

bitmap = mask & ~(left | down | right);

在参数之间应用OR操作,并按位翻转结果。

bit = -bitmap & bitmap;

bitmap的当前值(这里不会是0)的二进制补码,并屏蔽原始值。

bitmap ^= bit;

XOR操作应用于bitmap变量bit,该bitmap变量翻转1中位于bit backtrack(y + 1, (left | bit) << 1, down | bit, (right | bit) >> 1); 的任何位置{ {1}}。

left

将递归应用于下一个女王(行),将新bit设置为与right | bit合并的旧down | bit并向左移动以指示查看新文件(国际象棋中的“文件”)感)。它将0合并转换为右合并以指示新文件,并保留指示当前文件的size合并。

这样做的结果很容易将具有相互攻击向量的位置归零。除了在放置所有皇后之前达到满size, solutions, backtracks, millisec 0, 1, 1, 0 1, 1, 2, 0 2, 0, 3, 0 3, 0, 6, 0 4, 2, 17, 0 5, 10, 54, 0 6, 4, 153, 0 7, 40, 552, 0 8, 92, 2057, 0 9, 352, 8394, 0 10, 724, 35539, 1 11, 2680, 166926, 0 12, 14200, 856189, 16 13, 73712, 4674890, 116 14, 365596, 27358553, 702 15, 2279184, 171129072, 4318 16, 14772512, 1141190303, 30321 17, 95815104, 8017021932, 208300 的文件放置之外,尝试每种不同的文件放置组合。

这些位究竟是如何表明攻击向量是作为练习留下的。他们如何在import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppRoutingModule } from './app-routing.module'; // Imports for loading & configuring the in-memory web api import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; import { AppComponent } from './app.component'; import { DashboardComponent } from './dashboard.component'; import { HeroesComponent } from './heroes.component'; import { HeroDetailComponent } from './hero-detail.component'; import { HeroService } from './hero.service'; import { HeroSearchComponent } from './hero-search.component'; @NgModule({ imports: [ BrowserModule, FormsModule, HttpModule, InMemoryWebApiModule.forRoot(InMemoryDataService), AppRoutingModule ], declarations: [ AppComponent, DashboardComponent, HeroDetailComponent, HeroesComponent, HeroSearchComponent ], providers: [ HeroService ], bootstrap: [ AppComponent ] }) export class AppModule { } 位字段周围迁移是一个逐行跟踪循环的铅笔和纸张问题。

编辑:我没有提到它,但是这个算法处理对角线,正如规则中隐含的那样。

编辑:该程序版本的样本运行结果:

import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
  createDb() {
    let heroes = [
      {id: 11, name: 'Mr. Nice'},
      {id: 12, name: 'Narco'},
      {id: 13, name: 'Bombasto'},
      {id: 14, name: 'Celeritas'},
      {id: 15, name: 'Magneta'},
      {id: 16, name: 'RubberMan'},
      {id: 17, name: 'Dynama'},
      {id: 18, name: 'Dr IQ'},
      {id: 19, name: 'Magma'},
      {id: 20, name: 'Tornado'}
    ];
    return {heroes};
  }
}
相关问题