小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

特殊方格棋盤——狀態(tài)壓縮dp

 印度阿三17 2020-04-16

題面

在 n * n ( n <= 20 )?的方格棋盤上放置n?個車,某些格子不能放,求使它們不能互相攻擊的方案總數(shù)。

注意:同一行或同一列只能有一個車,否則會相互攻擊

輸入格式

輸入文件第一行,有兩個數(shù)n, m ,n表示方格棋盤大小,m表示不能放的格子數(shù)量

下面有m行,每行兩個整數(shù),為不能放的格子的位置。

輸出格式

輸出文件也只有一行,即得出的方案總數(shù)。

樣例

樣例輸入

2 1
1 1

樣例輸出

1

?

分析

一如既往的,狀態(tài)壓縮動態(tài)規(guī)劃。

限制分為兩部分:棋盤本身的限制 , ”車(ju)“自身的限制。

?

我們使用a數(shù)組記錄棋盤本身的限制即可,a [ x ]表示第x行限制情況所對應(yīng)的十進(jìn)制數(shù)字。?

?

這道題的有一個有意思的地方:一行里只能有一個車,一列里只能有一個車。

一行里只能有一個車,意思就是,我們可以只用一個二進(jìn)制串s,就可以表示之前所有行(包括目前行)一共放置的車的狀態(tài)了!

同時,這個限制串中"1"的個數(shù),就是我們目前所在的行號!

特別注意,這個s串中,包括目前行的那個“1”!

?

比如我們有限制串:01101

那么我們目前處在第三行。那么我們具有如下的情況:

目前第三行的狀態(tài)為:01000(即我在2號上放了一個車),則前兩行的合狀態(tài)為00101(前兩行里分別在3號和5號位置上放了車)

目前第三行的狀態(tài)為:00100(即我在3號上放了一個車),則前兩行的合狀態(tài)為01001(前兩行里分別在2號和5號位置上放了車)

目前第三行的狀態(tài)為:00001(即我在5號上放了一個車),則前兩行的合狀態(tài)為01100(前兩行里分別在2號和3號位置上放了車)

則我們定義f [ s ]為:在s串的狀態(tài)下,一共可能的放置方案數(shù)目。

注意,s本身就攜帶著“階段(行號)”和“狀態(tài)”兩層信息,所以動規(guī)數(shù)組 f 只用一維就可以了。

?我們再用Xi表示以前行的所有可能的合狀態(tài)(就是例子里我標(biāo)藍(lán)的部分,X1,X2,X3)

則有 f [ s ] = f [ X1 ] f [ X2 ] f [ X3 ] …… f [ Xi ]

?

那么如何實(shí)現(xiàn)是一個問題。我們有這個函數(shù):lowbit ( x )

如果不知道的話,可以百度。我在這里簡單說幾句

lowbit ( x ) 返回的是一個數(shù)x(二進(jìn)制形式)中,最低位的1,與其后的所有0,組成的的數(shù)值。

舉例一:100001110100111000

  該數(shù)字的lowbit值為“1000”,即8

舉例二:10001010

  該數(shù)字的lowbit值為“10”,即2

舉例三:1001

  該數(shù)字的lowbit值為“1”,即1

實(shí)現(xiàn)方式

?

int lowbit(int x){return (x&(-x));}

為什么這么做可以?利用了負(fù)數(shù)使用補(bǔ)碼儲存的原理。具體的自己去百度吧。

?

使用lowbit函數(shù),我們就可以使用這樣的方式來統(tǒng)計(jì),s數(shù)串里“1”的個數(shù),以獲取它所攜帶的行號信息:第“cnt”行

for(int i=s;i;i-=lowbit(i))cnt  ;//當(dāng)前是第cnt行

?

在執(zhí)行那個標(biāo)藍(lán)部分,和動態(tài)轉(zhuǎn)移的時候,我們使用這樣一種巧妙的方式來進(jìn)行尋找s所有子序列的工作

for(int i=s;i;i-=lowbit(i)){
    if(!(a[cnt] & lowbit(i))){
        int x=s^lowbit(i);
        f[s] =f[x];
    }
}

我們模擬一下:假設(shè)當(dāng)前s串為“ 010110010”

那么開始:

?

i 記錄:010110010;lowbit(i)=10,這個就是我們目前假設(shè)的本行車所在的位置。

“如果該行障礙 a [ cnt ]條件允許”,那么我們將原來s串010110010,中的“10“消去,變?yōu)?10110000,記錄為x。這個x就是之前行的合狀態(tài)。

將 f [ s ] 加上這一種之前合狀態(tài)的數(shù)目。

?

?i 減去 10,i記錄:010110000;lowbit ( i ) =10000,這個就是我們目前又假設(shè)的本行車所在位置的另一種情況。

“如果該行障礙 a [ cnt ]條件允許”,那么我們將原來s串010110010,中的“10000“消去,變?yōu)?10100010,記錄為x。這個x就是之前行的合狀態(tài)。

將 f [ s ] 加上這一種之前合狀態(tài)的數(shù)目。

?

i 減去 10000,i記錄:010100000;lowbit ( i ) =100000,這個就是我們目前又假設(shè)的本行車所在位置的另一種情況。

“如果該行障礙 a [ cnt ]條件允許”,那么我們將原來s串010110010,中的“100000“消去,變?yōu)?10010010,記錄為x。這個x就是之前行的合狀態(tài)。

將 f [ s ] 加上這一種之前合狀態(tài)的數(shù)目。

?

i 減去 100000,i記錄:010000000;lowbit ( i ) =10000000,這個就是我們目前又假設(shè)的本行車所在位置的另一種情況。

“如果該行障礙 a [ cnt ]條件允許”,那么我們將原來s串010110010,中的“10000000“消去,變?yōu)?00110010,記錄為x。這個x就是之前行的合狀態(tài)。

將 f [ s ] 加上這一種之前合狀態(tài)的數(shù)目。

?

i 減去10000000,i記錄:0循環(huán)停止。

這時候 f [ s ] 就是本s串的答案了!

?

那么再提醒一個點(diǎn)。根據(jù)我之前寫的那個玉米田的題,我們既然有n列,那么每一行就會有2^n -1種不同的s串 。

不同的是,由于我們這回首先預(yù)處理: f [ 0 ] =1,即一個不放也是一種情況,所以這回我們s串映射的就不再是0到2^n-1了,而是1到2^n?

不過最后輸出的時候,記得輸出 f [ 2^n -1 ]

而且注意longlong的問題。數(shù)目比較大,使用longlong。

?

代碼?

?

#include<cstdio>
#include<algorithm>
#include<cstring>
const int maxn=1<<20 1;
typedef long long ll;
ll f[maxn],a[25];//a記錄行障礙狀態(tài)
int lowbit(int x){return (x&(-x));}
int main(){
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i  ){
        int x,y;scanf("%d%d",&x,&y);
        a[x] =(1<<(y-1));
    }
    f[0]=1;//一個不放也是一種方案
    int maxs=1<<n;
    for(int s=1;s<=maxs;s  ){
        int cnt=0;
        for(int i=s;i;i-=lowbit(i))cnt  ;//當(dāng)前是第cnt行
        for(int i=s;i;i-=lowbit(i)){
            if(!(a[cnt] & lowbit(i))){
                int x=s^lowbit(i);
                f[s] =f[x];
            }
        }
    }
    printf("%lld\n",f[maxs-1]);
    return 0;
}

?

祝AC

?

來源:https://www./content-4-677151.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多