首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

N 皇後問題:位運算極致優化解法

     編輯:關於C語言

傳統回溯 vs 位運算

維度二維數組回溯位運算
空間O(N²)O(1) 僅幾個長整型
衝突檢測O(N) 掃描行/列/對角線O(1) 位與/或運算
代碼行數~50~30

位運算核心思想

  • 用整數的二進制位表示列佔用:第 i 位 = 1 表示第 i 列有皇后。
  • 三個掩碼:
    • row:列衝突
    • ld (left diagonal):左下對角線衝突(下一行左移 1 位)
    • rd (right diagonal):右下對角線衝突(下一行右移 1 位)
  • 可用位置:pos = upperlim & ~(row | ld | rd)(upperlim 低 N 位全 1)。
  • 取最低可用位:p = pos & -pos(隔離 lowest set bit)。
  • 遞歸:test(row|p, (ld|p)<<1, (rd|p)>>1)。

完整代碼

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

long sum = 0, upperlim = 1;

void test(long row, long ld, long rd) {
    if (row != upperlim) {
        long pos = upperlim & ~(row | ld | rd);
        while (pos) {
            long p = pos & -pos;        // 最右可用位
            pos -= p;                   // 移除該位
            test(row + p, (ld + p) << 1, (rd + p) >> 1);
        }
    } else {
        ++sum;                          // 找到一解
    }
}

int main(int argc, char* argv[]) {
    time_t tm = time(0);
    int n = (argc > 1) ? atoi(argv[1]) : 16;
    if (n < 1 || n > 32) { puts("1-32"); return -1; }

    upperlim = (upperlim << n) - 1;     // 低 n 位置 1
    printf("%d皇后 上限=%ld\n", n, upperlim);
    test(0, 0, 0);
    printf("共%ld種排列,耗時%d秒\n", sum, (int)(time(0)-tm));
    return 0;
}

關鍵技巧解析

  1. upperlim = (1<:生成掩碼 0b111...1 (n 個 1)。
  2. pos = upperlim & ~(row|ld|rd):同時排除列、兩條對角線衝突。
  3. p = pos & -pos:lowbit 技巧,取最低 1 位(對應最右可用列)。
  4. (ld+p)<<1 / (rd+p)>>1:下一行對角線衝突相對當前行左移/右移 1 列。

性能數據(參考)

N=13:  73712 解  <0.1s
N=14: 365596 解  ~0.3s
N=15: 2279184 解 ~2s
N=16: 14772512 解 ~14s

位運算版輕鬆解決 N≤16,N=32 理論可行但解數天文級。

擴展:輸出具體解

在遞歸參數中增加 long sol[32] 記錄每行皇后列位,row==upperlim 時打印。

總結

位運算將 N 皇后的「空間換時間」推向極致:幾個寄存器承載整個棋盤狀態,位級並行完成衝突檢測。這是算法優化中「數據結構位級壓縮」的教科書級範例。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved