1. 程式人生 > >算法復習——狀壓dp

算法復習——狀壓dp

script 目的 get cnblogs for in nbsp pen 情況 技術分享

狀壓dp的核心在於,當我們不能通過表現單一的對象的狀態來達到dp的最優子結構和無後效性原則時,我們可能保存多個元素的有關信息··這時候利用2進制的01來表示每個元素相關狀態並將其壓縮成2進制數就可以達到目的····此時熟悉相關的位運算就很重要了····以下是常見的一些需要位運算方法

技術分享

技術分享

然後說實話狀壓dp其它方面就和普通dp差不多了···它不像數位區間樹形那樣或多或少好歹有自己一定套路或規律····如何想到轉移方程和狀態也就成了其最難的地方···

例題:

1.Corn Fields(poj3254)

Description

Farmer John has purchased a lush new rectangular pasture composed of M

by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can‘t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input

Line 1: Two space-separated integers: M
and N
Lines 2..M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)

Output

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:
1 2 3
4

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9. 很明顯用二進制儲存每一排的種植情況f[i][j],i為行,j為種植狀態··每次枚舉判斷該行是否與玉米田本身沖突(不該種植的地方是否種上玉米),該行是否與自己沖突,該行是否與上一行沖突(相鄰地方是否種上玉米)然後更新就可以了。 另外這道題的時間復雜度註意是不會超的······放心枚舉····但要先枚舉上一行的合法狀態 然後不清楚位運算順序的(就是我)多打幾個括號吧2333 代碼:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=15;
const int mod=1e+8;
int f[N][5000],map[N],n,m,ans,maxx;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<0||c>9;c=getchar());
  for(;c<=9&&c>=0;c=getchar())
    f=(f<<3)+(f<<1)+c-0;
  return f;
}
inline void solve()
{
  for(int i=0;i<maxx;i++)
    if(((i|map[1])==map[1])&&!(i&(i>>1)))
      f[1][i]=1;
  for(int i=2;i<=n;i++)
    for(int j=0;j<maxx;j++)
      if(f[i-1][j])
        for(int k=0;k<maxx;k++)  
          if(((k|map[i])==map[i])&&!(k&(k>>1))&&!(k&j))
            f[i][k]=(f[i][k]+f[i-1][j])%mod;
  for(int i=0;i<maxx;i++)
    ans=(ans+f[n][i])%mod;
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R(),m=R();int a;maxx=(1<<m);  
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
      a=R();
      if(a)  map[i]|=(1<<(j-1));    
    }
  solve();
  cout<<ans<<endl;
  return 0;
}

算法復習——狀壓dp