K皇后問題_K皇后

來源:互聯網
上載者:User
K皇后問題
     FZU比賽殘留了一題搜尋題 K Queen 沒做, 題目大意就是在m*n的棋盤上布置k個皇后,使得這k個皇后互不攻擊(這裡的攻擊含義同“八皇后問題”,即兩個皇后不可以在同一行,同一列及同一斜線上)。其中1≤m*n≤150,1≤k≤50,時限10s
    
    其實從題目中我們可以推出一個很簡單但是很重要的結論,即min(m, n) < 13, 言下之意就是說這個棋盤的較短的一邊長度不會超過12,這樣就不會對150這個數字感到恐懼了。同樣,我們可以斷言 k <= min(m, n)。另外一個簡單的結論是
f[m][n][k] = f[n][m][k] (f[m][n][k]表示m*n的棋盤放置k個互不攻擊的皇后種數)

    其次,我們可能想到直接回溯進行硬搜,那很不幸這樣是行不通的。為什麼行不通,很多相似的狀態進行重複的搜尋,我們需要把那些相似狀態給去除掉,也就是要加上一個強力的剪枝才行。 不難發現,我們要處理的是一個棋盤,而棋盤具有某些對稱的性質。通過利用這些性質我們可以有效減少搜尋空間,從而使得效率得到很大提升。(理論上說應該能減少1/4,我在使用過程中為了方便,減少了1/2)

   能否更快些呢。記得以前在群裡頭聽討論說n皇后有個超快的位元運算版本,上網搜了搜,發現確實很強悍,如果配合上位元運算再加上對稱性,那是相當的完美了。(關於n皇后位元運算版本的介紹可以參加matrix67的blog的 這篇文章)

   下面是AC的代碼,6.2s
//農夫三拳@seu#include <stdio.h>#include <string.h>typedef long long i64;i64 s[151][151][51];int m, n, x, y;int MASK;i64 ans;void dfs(int m, int n, int row, int ld, int rd, int num, int p, int index){    if(num == p)        ans++;    else if(index < m)    {        if(num + m - index > p)            dfs(m, n, row, ld << 1, rd >> 1, num, p, index + 1);        int pos = MASK & ~(row | rd | ld);        while(pos != 0)        {            int pp = pos & -pos;            pos = pos - pp;            dfs(m, n, row + pp, (ld + pp) << 1, (rd + pp) >> 1, num + 1, p, index + 1);        }    }}i64 solve(int m, int n, int p){    if(s[m][n][p] != -1)        return s[m][n][p];    if(p > n)        return 0;    i64 ret = 0;    int i, j;    for(j = 0; j < n; j++)    {        int pos = 1 << (n - 1 - j);        ans = 0;        dfs(m, n, pos, pos << 1, pos >> 1, 1, p, 1);         ret += ans;    }        s[m][n][p] = ret;    return ret;}int main(){    int i, j;    memset(s, -1, sizeof(s));    while(scanf("%d%d%d%d", &m, &n, &x, &y) == 4)    {        if(m < n && n > 31)        {            int t = m;            m = n;            n = t;        }        if(y > n)            y = n;        MASK = (1 << n) - 1;        i64 res = 0;        if(x == 0)            res++, x = 1;        for(i = x; i <= y; i++)        {            for(j = i; j <= m; j++)                res += solve(j, n, i);        }        printf("%lld\n", res);    }    return 0;}


後記:
1. 通過實驗發現,當給定m*n(n > m)棋盤的時候,在n < 31的範圍以內盡量使n較大,反之將m,n進行交換處理,這樣可以充分的利用int範圍內的位元運算的效果。 其實當用64位的位元運算之後,速度反而降下來了。
2. 如果利用一行的對稱型,我們只要枚舉第一個皇后在某行的列的一半就可以了 轉自:http://www.cnblogs.com/drizzlecrj/archive/2007/10/04/913703.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.