国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一文帶你入門并吃透狀態(tài)壓縮DP

這篇具有很好參考價(jià)值的文章主要介紹了一文帶你入門并吃透狀態(tài)壓縮DP。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

【本文比較適合有一定動(dòng)態(tài)規(guī)劃和位運(yùn)算基礎(chǔ)的童鞋閱讀】

首先先講講什么是狀態(tài)壓縮

狀態(tài)壓縮就是使用某種方法,簡明扼要地以最小代價(jià)來表示某種狀態(tài),通常是用一串01數(shù)字(二進(jìn)制數(shù))來表示各個(gè)點(diǎn)的狀態(tài)。這就要求使用狀態(tài)壓縮的對(duì)象的點(diǎn)的狀態(tài)必須只有兩種,0 或 1

我們都知道二進(jìn)制可以用來枚舉子集,例如某個(gè)問題有8種情況,那么我們可以一個(gè)循環(huán),從0到2^3-1,將所有情況枚舉出來,這里拓展一個(gè)位運(yùn)算的技巧(i>>j&1): 用來求十進(jìn)制下的數(shù)i第j位是否為1,我們規(guī)定如果當(dāng)前位為1就說明這一位應(yīng)當(dāng)被選中

動(dòng)態(tài)規(guī)劃的問題

狀態(tài)壓縮DP常見問題大概可以分為兩類

1.棋盤式(基于連通性)DP

2.集合式DP

個(gè)人總結(jié)的狀態(tài)壓縮dp三部曲:

  1. 考慮如何狀態(tài)壓縮

  2. 確定狀態(tài)表示和狀態(tài)轉(zhuǎn)移方
  3. 根據(jù)實(shí)際問題確定篩選條件 最關(guān)鍵一步!??!合理情況的篩選一定要考慮完全

解釋一下第三步的原因,我們狀態(tài)壓縮是對(duì)所有情況進(jìn)行枚舉,而實(shí)際的題目中會(huì)有限制,我們根據(jù)題目要求,先對(duì)所有情況進(jìn)行預(yù)處理,用一個(gè)bool數(shù)組,將不合法的數(shù)值標(biāo)記為false即可

例題引入:?P1879 [USACO06NOV]Corn Fields G - 洛谷 | 計(jì)算機(jī)科學(xué)教育新生態(tài) (luogu.com.cn)

題意:每一個(gè)是1的都可以種植草地,每個(gè)草地的上下左右不能有草地,求方案數(shù)

第一步:分析如何狀態(tài)壓縮

規(guī)定1表示種植草地,0表示不種值,所以每一行的狀態(tài)由[0,2^m-1]表示,m表示列數(shù)?

第二步:狀態(tài)表示和狀態(tài)轉(zhuǎn)移方程

初狀態(tài) f[0][0] = 1(默認(rèn)一行也不擺也是一種方案)

f[i][j]表示擺完了前i行,第i行的狀態(tài)是j的方案數(shù)

第i行是在前i-1的基礎(chǔ)上加上的所以狀態(tài)轉(zhuǎn)移方程很容易得出:f[i][j] += f[i-1][k];?

第三步: 根據(jù)實(shí)際情況篩選合理情況

本題中要求若中間確定種植草地,則上下左右不允許出現(xiàn)草地,即不允許出現(xiàn)1

我們可以通過位運(yùn)算來確定是否合法

1.行內(nèi)合法 位運(yùn)算技巧: !(i & i >> 1)為真,則為合法情況

技巧講解: i>>1后i-1位來到了i位,i位來到了i+1位的情況,如果i&i>>1等于0不就是說明i-1和i,i和i+1都是不相等的狀態(tài)嗎,也就是我們當(dāng)前第i位是1,那么i-1位和i+1位都是0,就保證了左右沒有草地

2.行間是否合法?

我們假設(shè)第i-1行的狀態(tài)是a,第i行的狀態(tài)是b,那么需要滿足的條件是!(a&b),就是兩行間不能有相鄰的草地,

3.枚舉的狀態(tài)數(shù)是否符合實(shí)際的條件

本題的實(shí)際條件就是不能超過本行的草地?cái)?shù)量

例如一個(gè)3行5列的土地,當(dāng)前行只有兩列是可以種植草地的,所以當(dāng)前土地的草地?cái)?shù)為g[i],那么應(yīng)該滿足a&g[i] = a,就是a應(yīng)該是g[i]的一個(gè)子集,相當(dāng)于a∩g[i] = a

#include<iostream>
using namespace std;
const int mod = 1e9;
int g[14];
int s[1<<14];//s數(shù)組用來存儲(chǔ)狀態(tài),所以列數(shù)[1,12],所以可以開到2^14
int f[14][1<<14];f數(shù)組是動(dòng)態(tài)規(guī)劃的數(shù)組,第一維表示行數(shù),第二維表示當(dāng)前狀態(tài)
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            int x;
            cin>>x;
            g[i] = (g[i] << 1) + x;//位運(yùn)算
        }
    }
    int cnt = 0;
    for(int i = 0;i < (1<<m);i++)
    {
        if(!(i&i>>1)) s[cnt++] = i;//預(yù)處理,將符合條件的狀態(tài)存下來
    }
    f[0][0] = 1;//初始
    for(int i = 1;i <= n;i++)
    {
        for(int a = 0;a < cnt;a++)
        {
            for(int b = 0;b < cnt;b++)
            {
                if((g[i]&s[a]) == s[a] && !(s[a] &s[b]))//過濾行間和行內(nèi)要滿足的條件
                  f[i][a] = (f[i-1][b] + f[i][a]) % mod; //狀態(tài)轉(zhuǎn)移
            }
        }
    }
    long long ans ;
    for(int i = 0;i < cnt;i++) //遍歷所有狀態(tài),將第n行的合理狀態(tài)加起來
    {
        ans =(ans + f[n][i]) % mod;
       
    }
    cout<<ans;
}

最后遍歷所有的合理狀態(tài)也可以根據(jù)狀態(tài)轉(zhuǎn)移方程,第n+1的方案是由第n行轉(zhuǎn)移過來的,

所以f[n+1][0] = (f[n][a1] + f[n][a2] + .....f[n][acnt]),也就是相當(dāng)于遍歷了一遍,所以我們也可以這樣寫

for(int i = 1;i <= n+1;i++)//循環(huán)到第n+1行
    {
        for(int a = 0;a < cnt;a++)
        {
            for(int b = 0;b < cnt;b++)
            {
                if((g[i]&s[a]) == s[a] && !(s[a] &s[b]))
                  f[i][a] = (f[i-1][b] + f[i][a]) % mod; 
            }
        }
    }
    cout<<f[n+1][0];

例題引入 :U204941 蒙德里安的夢(mèng)想 - 洛谷 | 計(jì)算機(jī)科學(xué)教育新生態(tài) (luogu.com.cn)

第一步 首先先給出一個(gè)明顯的結(jié)論:橫放格子的方案數(shù)等于總方案數(shù)

當(dāng)豎放的格子確定好位置后,那么橫放的格子也就確定了,因?yàn)閿[放的方式只有橫放或者豎放,當(dāng)豎放確定后,剩余的坑位也就確定了形狀,顯然這題就是討論哪個(gè)格子是怎么放置的,我們看它給出的數(shù)據(jù)范圍是[1,11],我們可以考慮按列擺放,那么我們枚舉二進(jìn)制,根據(jù)題目實(shí)際分析應(yīng)該是[0,2^m-1],行數(shù)是n,那么就有n位。

我們可以規(guī)定若某行是1,表示橫,某行為0,表示豎放。

第二步

?用f[i][j]記錄第i列第j個(gè)狀態(tài)。j狀態(tài)位等于1表示上一列有橫放格子,本列有格子捅出來。轉(zhuǎn)移方程很簡單,本列的每一個(gè)狀態(tài)都由上列所有“合法”狀態(tài)轉(zhuǎn)移過來f[i][j] += f[i - 1][k]

初始化條件:f[0][0] = 1第0列只能是狀態(tài)0,無任何格子捅出來。

終止?fàn)顟B(tài):f[m+1][0]。第m + 1列不能有東西捅出來。

第三步

分析實(shí)際情況:

那么在這個(gè)題中我們應(yīng)該可以想到第i列和第i-1不能為同時(shí)為1,因?yàn)槲覀円?guī)定有1表示當(dāng)前的列是橫放格子的第二個(gè)格子,如果i列為1就說明i-1列應(yīng)該是豎放格子的第一個(gè)

所以條件為!(j&k)為真

第二個(gè)條件:設(shè)當(dāng)前列的狀態(tài)是state,,上一列狀態(tài)為last,我們知道是把行作為狀態(tài)數(shù),說明這一行有格子,那么我們沒有格子的地方最后是要填滿豎放格子的,豎放格子的高為2,也就是我們兩個(gè)放格子的行之間的行數(shù)應(yīng)該是偶數(shù)個(gè),如果是奇數(shù)個(gè)不能放下豎放格子,肯定會(huì)有空格,所以state|last 應(yīng)該是不能出現(xiàn)連續(xù)奇數(shù)個(gè)0,這個(gè)條件我們可以通過預(yù)處理,將滿足條件的狀態(tài)存下來,下面通過圖來解釋

綠色為上一列的格子,藍(lán)色表示這一列的格子,last |state 就是兩個(gè)狀態(tài)只要出現(xiàn)1,最后的結(jié)果的這一行就為1,因?yàn)閮蓚€(gè)狀態(tài)的交集在第i列,無論是i-1列的狀態(tài)出現(xiàn)1還是i列出現(xiàn)1,都有第i列肯定有格子,只有兩個(gè)狀態(tài)的當(dāng)前行都為0,第i列的格子才沒有被填,所以我們要找的就是 state|last中是否有連續(xù)的0

?一文帶你入門并吃透狀態(tài)壓縮DP

#include<iostream>
#include<cstring>
using namespace std;
const int N = 13,M = 1<<N;
long long f[N][M];
int cnt;
bool st[M];
int main()
{
    
       int n,m;
       while(cin>>n>>m,n||m)
       {
           memset(f,0,sizeof f);
           for(int i = 0;i < (1<<n);i++)
           {
               cnt = 0;
               st[i] = true;
               for(int j = 0;j < n;j++)
               {
                   if(i >> j & 1)
                   {
                      if(cnt & 1)
                      {
                          st[i] = false;
                          cnt = 0;
                      }
                     
                   }
                   else cnt++;
               }
                if(cnt & 1) st[i] = false;
           }
           f[1][0] = 1;//初始條件 第一列不能作為橫放格子的第二個(gè)格子,只有0一種情況
           for(int i = 2;i <= m+1;i++)
           {
               for(int j = 0;j < (1<<n);j++)
               {
                   for(int k = 0;k <(1<<n);k++)
                   {
                       if(!(j & k)&& st[j|k]) f[i][j] += f[i-1][k];
                   }
               }
           }
           cout<<f[m+1][0]<<endl;//第m+1行應(yīng)該是沒有格子的情況
       }
}

例題引入:P1896 [SCOI2005] 互不侵犯 - 洛谷 | 計(jì)算機(jī)科學(xué)教育新生態(tài) (luogu.com.cn)

題意很好理解,就是說如果當(dāng)前點(diǎn)放了國王,以它為中心的九宮格都不能放置國王

二:狀態(tài)表示:f[i][j][a]:表示前i行放了j個(gè)國王,第i行狀態(tài)為a的方案數(shù)

狀態(tài)轉(zhuǎn)移:用c數(shù)組存儲(chǔ)當(dāng)前行的為a狀態(tài)時(shí)的國王數(shù)

f[i][j][a] += f[i-1][j-c[k][b];

三.篩選條件

?1.行內(nèi)合法:與它左右的方格不能同時(shí)放1,!(i&i>>1)為真

2.行間合法:和它的上,左上,右上,下都不能同時(shí)放1,!(a&b),!(a&b>>1),!(a&b<<1)都為真時(shí),才可以兼容

#include<iostream>
using namespace std;
long long f[14][144][1<<12];
int nums[1<<12];
int s[1<<12];
int n,cnt;
void init()
{
    for(int i = 0;i < (1<<n);i++)
    {
       if(i&(i>>1)) continue;
       s[cnt++] = i;
       for(int j = 0;j < n;j++)
       {
           nums[i] += (i>>j&1);//存儲(chǔ)每個(gè)狀態(tài)表示里行間合格的國王數(shù)
       }
    }
}
int main()
{
   
    int k;
    cin>>n>>k;
    init();//預(yù)處理行間
    f[0][0][0]=1;
    for(int i = 1;i <= n+1;i++)//小技巧:遍歷到n+1,那么i+1行的方案數(shù)都由i行轉(zhuǎn)移,所有方案都存儲(chǔ)在i+1行中
    {
        for(int j = 0;j <= k;j++)
        {
            for(int a = 0;a < cnt;a++)
            {
                for(int b = 0;b < cnt;b++)
                {
                    int c = nums[s[b]];
                    if(j - c >= 0 && !(s[a] & s[b]) && !(s[a] & (s[b]>>1)) && !(s[a]&(s[b]<<1)))
                    {
                        f[i][a][j] += f[i-1][b][j-c];
                    }
                }
            }
        }
    }
  //  cout<<cnt<<endl;
    cout<<f[n+1][0][k];
}

例題引入?P2704 [NOI2001] 炮兵陣地 - 洛谷 | 計(jì)算機(jī)科學(xué)教育新生態(tài) (luogu.com.cn)

這道題和第一題十分相似,但是要求是上下左右各多了一格。

狀態(tài)表示 f[i][a][b] :第i行的狀態(tài)為a,i-1行狀態(tài)為b。

狀態(tài)轉(zhuǎn)移 f[i][a][b] 是由上一行f[i-1][b][c]轉(zhuǎn)移而來。

篩選條件

1.行內(nèi):!(i&i>>2)和!(i&i>>1)同時(shí)為真

2.行間? a,b,c相與必須為0

3.不能在山地上布署文章來源地址http://www.zghlxwxcb.cn/news/detail-493676.html

#include<iostream>
using namespace std;
int g[110];
int cnt;
int num[1<<10];
int s[1<<10];
int f[2][1<<10][1<<10];

int main()
{
    int n,m;
    cin>>n>>m;
     for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            char ch;
            cin>>ch;
            int x = 0;
            if(ch == 'P') x = 1;
            g[i] = (g[i]<<1) + x;
        }
    }
    for(int i = 0;i < (1<<m);i++)
    {
        if(!(i & i >>1)&&!(i & i >>2)) 
        {
            s[cnt++] = i;
            for(int j = 0;j < m;j++)
            {
                num[i] += (i >> j & 1);
            }
        }
    }
   // cout<<cnt<<endl;
   //f[0][0][0] = 1;
    for(int i = 1;i <= n +2;i++)
    {
        for(int a = 0;a < cnt;a++)
        {
            for(int b = 0;b < cnt;b++)
            {
                for(int c = 0;c < cnt;c++)
                {
                    if(!(s[a]&s[b]) && !(s[a]&s[c]) && !(s[b]&s[c]) && (g[i-1]&s[b])==s[b] &&(g[i]&s[a])==s[a])
                    {
                        f[i&1][a][b] = max(f[i&1][a][b],f[i-1&1][b][c]+num[s[a]]);
                    }
                }
            }
        }
    }
    cout<<f[n+2&1][0][0];
    return 0;
}

到了這里,關(guān)于一文帶你入門并吃透狀態(tài)壓縮DP的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【W(wǎng)eb前端】一文帶你吃透CSS(中篇)

    【W(wǎng)eb前端】一文帶你吃透CSS(中篇)

    前端學(xué)習(xí)路線小總結(jié) : 基礎(chǔ)入門: HTML CSS JavaScript 三大主流框架: VUE REACT Angular 深入學(xué)習(xí): 小程序 Node jQuery TypeScript 前端工程化

    2023年04月25日
    瀏覽(95)
  • 【W(wǎng)eb前端】一文帶你吃透CSS(完結(jié)篇)

    【W(wǎng)eb前端】一文帶你吃透CSS(完結(jié)篇)

    前端學(xué)習(xí)路線小總結(jié) : 基礎(chǔ)入門: HTML CSS JavaScript 三大主流框架: VUE REACT Angular 深入學(xué)習(xí): 小程序 Node jQuery TypeScript 前端工程化

    2024年01月20日
    瀏覽(88)
  • 【Spring】一文帶你吃透基于注解的DI技術(shù)

    【Spring】一文帶你吃透基于注解的DI技術(shù)

    個(gè)人主頁: 幾分醉意的CSDN博客_傳送門 基于注解的DI:使用spring提供的注解,完成java對(duì)象創(chuàng)建,屬性賦值。 注解使用的核心步驟: 1.在源代碼加入注解,例如@Component。 2.在spring的配置文件,加入組件掃描器的標(biāo)簽。 @Component: 表示創(chuàng)建對(duì)象,對(duì)象放到容器中。 作用是 聲明組件

    2024年02月03日
    瀏覽(82)
  • 一文帶你吃透JSP,增刪改查實(shí)戰(zhàn)案例詳細(xì)解讀

    一文帶你吃透JSP,增刪改查實(shí)戰(zhàn)案例詳細(xì)解讀

    不得不說,JSP 現(xiàn)在已經(jīng)是一門十分老舊的技術(shù)了,學(xué)習(xí)編程時(shí),不僅要學(xué)習(xí)優(yōu)秀的前言技術(shù),還要對(duì)基礎(chǔ)有一定的把握,所以學(xué)習(xí) JSP 時(shí),我們只做了解,不用刨根問底花費(fèi)大量的時(shí)間,得不償失。 我們主要從以下幾個(gè)方面學(xué)習(xí) JSP 技術(shù): 理解 JSP 及其原理 學(xué)會(huì)使用 EL 表達(dá)

    2024年02月03日
    瀏覽(81)
  • 【Spring】一文帶你吃透AOP面向切面編程技術(shù)(上篇)

    【Spring】一文帶你吃透AOP面向切面編程技術(shù)(上篇)

    個(gè)人主頁: 幾分醉意的CSDN博客_傳送門 什么是AOP? AOP(Aspect Orient Programming):面向切面編程 Aspect:表示切面,給業(yè)務(wù)方法增加的功能,叫做切面。切面一般都是非業(yè)務(wù)功能,而且切面功能一般都是可以復(fù)用的。例如日志功能,事務(wù)功能,權(quán)限檢查,參數(shù)檢查,統(tǒng)計(jì)信息等等

    2024年01月16日
    瀏覽(86)
  • 【C++】一文帶你吃透string的模擬實(shí)現(xiàn) (萬字詳解)

    【C++】一文帶你吃透string的模擬實(shí)現(xiàn) (萬字詳解)

    (???(??? )??,我是 Scort ?? ??博客主頁:張小姐的貓~江湖背景 快上車??,握好方向盤跟我有一起打天下嘞! 送給自己的一句雞湯??: ??真正的大師永遠(yuǎn)懷著一顆學(xué)徒的心 作者水平很有限,如果發(fā)現(xiàn)錯(cuò)誤,可在評(píng)論區(qū)指正,感謝?? ????歡迎持續(xù)關(guān)注! ??傳統(tǒng)寫

    2024年02月03日
    瀏覽(95)
  • 如何使用JDBC操作數(shù)據(jù)庫?一文帶你吃透JDBC規(guī)范

    如何使用JDBC操作數(shù)據(jù)庫?一文帶你吃透JDBC規(guī)范

    大家好,我是橙子。最近又肝了幾個(gè)大夜,總結(jié)了 JDBC 完整版的基礎(chǔ)教程和實(shí)戰(zhàn)案例訓(xùn)練??靵砜纯催@些 Java 基礎(chǔ)性的代碼你有沒有忘記? 在 Java 開發(fā)中,使用 Java 語言操作數(shù)據(jù)庫是非常重要的一部分,那么 Java 語言是如何操作數(shù)據(jù)庫的呢? 我們需要使用不同廠商的數(shù)據(jù)庫

    2024年02月03日
    瀏覽(1673)
  • 【Kubernetes 系列】一文帶你吃透 K8S 應(yīng)用pod結(jié)點(diǎn)

    【Kubernetes 系列】一文帶你吃透 K8S 應(yīng)用pod結(jié)點(diǎn)

    作者:半身風(fēng)雪 上一節(jié):創(chuàng)建K8s集群項(xiàng)目 簡介:上一節(jié)我們一起學(xué)習(xí)了,如何去部署一個(gè)K8S 的應(yīng)用程序,這一節(jié),我們主要講解一下,K8S 應(yīng)用的框架結(jié)構(gòu)。 本節(jié)我將和大家一起學(xué)習(xí)Kubernetes 應(yīng)用中的pod結(jié)點(diǎn) 了解 Kubernetes Pod。 了解 Kubernetes 工作節(jié)點(diǎn)。 對(duì)已部署的應(yīng)用故障排

    2023年04月08日
    瀏覽(710)
  • C++ 動(dòng)態(tài)規(guī)劃 狀態(tài)壓縮DP 最短Hamilton路徑

    C++ 動(dòng)態(tài)規(guī)劃 狀態(tài)壓縮DP 最短Hamilton路徑

    給定一張 n 個(gè)點(diǎn)的帶權(quán)無向圖,點(diǎn)從 0~n?1 標(biāo)號(hào),求起點(diǎn) 0 到終點(diǎn) n?1 的最短 Hamilton 路徑。 Hamilton 路徑的定義是從 0 到 n?1 不重不漏地經(jīng)過每個(gè)點(diǎn)恰好一次。 輸入格式 第一行輸入整數(shù) n 。 接下來 n 行每行 n 個(gè)整數(shù),其中第 i 行第 j 個(gè)整數(shù)表示點(diǎn) i 到 j 的距離(記為 a[

    2024年02月19日
    瀏覽(24)
  • acwing算法基礎(chǔ)之動(dòng)態(tài)規(guī)劃--數(shù)位統(tǒng)計(jì)DP、狀態(tài)壓縮DP、樹形DP和記憶化搜索

    acwing算法基礎(chǔ)之動(dòng)態(tài)規(guī)劃--數(shù)位統(tǒng)計(jì)DP、狀態(tài)壓縮DP、樹形DP和記憶化搜索

    暫無。。。 暫無。。。 題目1 :求a~b中數(shù)字0、數(shù)字1、…、數(shù)字9出現(xiàn)的次數(shù)。 思路:先計(jì)算1~a中每位數(shù)字出現(xiàn)的次數(shù),然后計(jì)算1~b-1中每位數(shù)字出現(xiàn)的次數(shù),兩個(gè)相減即是最終答案。 那么,如何計(jì)算1~a中每位數(shù)字出現(xiàn)的次數(shù)呢? 首先,將a的每一位存入向量num中,例如a=123

    2024年02月04日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包