狀壓dp本人做的題目真的不太多...至今還未理解到其中的精髓.所以以下的思路
描述中有存在不當的地方希望能夠指出.另外,有些地方說的比較複雜,因為本弱雞
對這些東西不是很理解.....多寫點有助於理解吧.
poj 1185 經典狀壓dp
我隊友這篇博文還不錯.
思路:
首先,我們可以發現對於每一行的當前位置能不能放炮兵,只與他的上一行和上上一行
的炮兵位置有關係,所以要開乙個三維陣列轉移關係.
0表示不放大炮,1表示放大炮,同樣的,先要滿足硬體條件,即有的地方不能放大炮,
然後就是每一行中不能有兩個1的距離小於2(保證橫著不互相攻擊),這些要預先處理一下。然後就是
狀態表示和轉移的問題了,因為是和前兩行的狀態有關,所以要開個三維的陣列來表示狀態,當前行
的狀態可由前兩行的狀態轉移而來。即如果當前行的狀態符合前兩行的約束條件(不和前兩行的大炮
互相攻擊),則當前行的最大值就是上乙個狀態的值加上當前狀態中1的個數(當前行放大炮的個數)
【狀態表示】dp[i][j][k] 表示第i行為第j個狀態,第i-1為第k個狀態時的最大炮兵個數。
【狀態轉移方程】 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);//num[j]為第j個狀態中的二進位制1的個數
【dp邊界條件】dp[1][i][0] =num[i] 狀態i能夠滿足第一行的硬體條件
(注意:這裡的i指的是第i個狀態,不是乙個二進位制數,開乙個陣列儲存二進位制狀態)
思考:對於這種有地形限制的,標記乙個點其他周圍都有影響的,一般都要預處理.將所有可能的狀態
和地形的限制預處理出來,
每次列舉第i個狀態的時候,要首先滿足地形的限制,在滿足各行各列之間
的關係.
#include#include#include#includeusing namespace std;
const int maxn=111;
int dp[maxn][maxn][maxn];//dp[i][j][k] 第i行為第j個狀態,第i-1行為第k個狀態時的最大炮兵數
int status[maxn],num[maxn]; //status[i] 當前第i個狀態的二進位制 kk(1放大炮 0 不放).
//num[i]存放與status相對應的當前的第i個狀態的二進位制中有多少個1,即放了多少炮兵
char s[maxn];
int mp[maxn];//存放地形的限制,1表示不能放大炮,0表示可以放大炮.
int n,m;
int _count(int x)
return __;
}int main()
return _;
}int check_row(int r,int i)//判斷第r行的第i個狀態和r的地形是否衝突
int check_sta(int i,int j)//判斷第i個狀態和第j個狀態是否衝突。
int main()
{ scanf("%d",&t);
while(t--)
{memset(dp,0,sizeof(dp));
memset(mp,0,sizeof(mp));
memset(status,0,sizeof(status));
memset(num,0,sizeof(num));
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{int x;
for(int j=0;j
狀態壓縮DP總結
參考部落格 狀態壓縮主要指的是用位運算代替列舉壓縮dp的時間,如果某乙個狀態和之前狀態的順序沒有關係,那麼就可以將之前的選或者不選壓縮到乙個二進位制數中。在選擇第i個時列舉之前的所有可能的i 1狀態,但是這i 1狀態是不記錄順序的,只在i 1到i時考慮順序,這樣的話往往能夠節約很多時間。大致題意是從...
狀壓dp(總結)狀態壓縮
狀壓這個和二進位制分不開關係 所以,對於二進位制的熟悉是必不可少的技能 與操作,1不變,0變0 或操作,0不變,1變1 異或操作,0不變,1取反 取反操作,把每乙個二進位制位0變1,1變0 還有一些複雜操作可以根據這些去理解 狀態壓縮 所謂狀態壓縮就是把dp的每一次轉移時的狀態用二進位制來表示 或者...
狀態壓縮DP
首先,我們以一道狀壓經典題tsp來引入。tsp問題 一張圖上有n個點,給定相應的鄰接矩陣,需要求出從0號節點出發,經過且只經過每個頂點一次,最後仍回到0號節點的最小邊權。思路 假設現在已訪問過的頂點集合 起點0當作還未訪問過的頂點 為s,當前所在頂點為v,用dp s v 表示從v出發訪問剩餘的所有頂...