簡易狀態壓縮DP
簡易狀壓DP
開頭甩定義
藉助二進位制完成對狀態的壓縮,從而進行動態規劃的過程,我們稱之為狀態壓縮動態規劃(簡稱“狀壓DP”)
位運算
-
左移右移
左移:左移一位,等價於該數x2
eg. 110<<1 = 1100 (十進位制從6變為12)
右移同理
eg. 110>>1 = 11(十進位制從6變為3) -
與或非
相信各位OIer應當在普及時就學過位運算了,但本蒟蒻還是要講
與:按位進行與運算 滿足兩數同一位都為1時結果為1,否則為0
或:按位進行或運算 滿足兩數同一位都為0時結果為0,否則為1
非:按位取反 -
簡單運算
當我們需要判斷或修改二進位制數S的第i位時,我們進行以下操作
若判斷第i位是否為0 即判斷 (S&(1<<i)) 是否為0
若要將第i位設定為1 即 (S|(1<<i)) 即1左移i位於S進行或運算
若要將第i位設定為0 即 (S&~(1<<i)) 即S與只有第i位為0的數進行或運算 -
簡單應用
經過上面的學習大家可以發現我們可以用位運算的方法來列舉子集
假設集合A={1,2,3,4,5}
我們可以通過將A中的數編號的方式使其轉化為一個二進位制數
是不是非常神奇呀
下面我們來康康具體操作
假設我們要表示A的子集B={2,4,5}
二進位制數位 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|
二進位制值 | 1 | 1 | 0 | 1 | 0 |
子集元素 | 5 | 4 | 0 | 2 | 0 |
這裡需要注意的是二進位制的數位是從0開始的,所以對應關係不要找錯
所以B集合用二進位制就可以表示為11010啦!!
那麼我們來做個練習
李白打酒 【2014藍橋杯預賽】
話說大詩人李白,一生好飲。
一天,他提著酒壺,從家裡出來,酒壺中有酒兩鬥。他邊走邊唱:
無事街上走,提壺去打酒
逢店加一倍,遇花喝一斗。
這一路上,他一共遇到店5次,遇到花10次,已知最後一次遇到的是花,他正好把酒喝光了。請你計算李白有多少種滿足要求的遇到店和花的可能情況
輸入
無
正確輸出
14
題解:
一道簡單的練手題
考慮使用01串表示遇到花或者店,因為最後一個一定是花所以列舉14位01串就OK
程式碼放送~
#include <bits/stdc++.h>
using namespace std;
int main()
{
int ans=0;
for(int i=0;i<(1<<14);i++)//列舉每種情況
{
int ans1=0,ans2=0;
int num=2;
for(int j=0;j<14;j++)
{
if(i&(1<<j))
{
ans1++;
num*=2;
}
else {ans2++;num--;}
}
if(ans1==5&&ans2==9&&num==1)ans++;//特判
}
cout<<ans;
}
好的你已經掌握了基本的位運算知識了讓我們來康康簡單狀壓DP
狀壓DP
話不多說直接上題
國王 [SGU 223]
在 n×n 的棋盤上放 k 個國王,國王可攻擊相鄰的 8 個格子,求使它們無法互相攻擊的方案總數
輸入
只有一行,包含兩個整數 n 和 k
輸出
每組資料一行為方案總數,若不能夠放置則輸出 0
樣例輸入
3 2
樣例輸出
16
1<=n<=10 , k<=n2
題解
本題為狀態壓縮DP入門題
這個題使用八皇后做法是顯然不行的(很難剪枝),就考慮使用DP,然而國王在棋盤上的狀態使用傳統的f[i][j]很難表示,由於國王的狀態只有兩種,放置與不放置,所以考慮狀壓解決
對於第i行所擺放的國王,只會有第i-1行和第i+1行的國王影響它,對其的影響是i-1行和i+1行的擺放方式和1~i-1行總共擺放的國王數很容易得出初始的動態方程
令f[i][j][s]為第i行目前擺放狀態a[j]和前i行已經擺放的國王個數s,易得
f[i][j][s]=∑f[i-1][k][t]
a[j],a[k]為兩種不同擺放方式
那麼接下來我們就要想想如何表示這兩種狀態
還記得我們之前說的李白問題嗎?不記得就回去看
看見國王在棋盤上擺放的狀態只有兩種,擺與不擺,那麼我們可以嘗試使用一個01串表示狀態,又因為一排最多10個格子,最大寬度也滿足,考慮:
(蒟蒻表格,@代替下國王,沒有就是x)
@ | x | x | x | @ | x |
---|---|---|---|---|---|
1 | 0 | 0 | 0 | 1 | 0 |
如上圖,每個格子對應一個二進位制位,於是乎狀態就可以用一個卡哇伊的 二進位制數表示出來啦
時間複雜度也是允許的,可以自己推推看~
放程式碼!!
#include<bits/stdc++.h> //萬能庫深得朕心
using namespace std;
typedef long long ll;
#define N 15
ll f[N][155][155],ans=0,s=0;
int n,sum[166],num[155],K;
int main()
{
cin>>n>>K;
memset(f,0,sizeof(f));
for(int i=0;i<(1<<n);i++)
{
if(i&(i<<1)) continue; //檢查狀態
int k=0;
for(int j=0;j<n;j++) if(i&(1<<j))k++;
sum[++s]=i;
num[s]=k;
}
f[0][1][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=s;j++)
for(int k=0;k<=K;k++)
{
if(k>=num[j])
for(int t=1;t<=s;t++)
if(!(sum[t]&sum[j])&&!(sum[t]&(sum[j]<<1))&&!(sum[t]&(sum[j]>>1)))
f[i][j][k]+=f[i-1][t][k-num[j]];
}
for(int i=1;i<=s;i++) ans+=f[n][i][K]; //統計
cout<<ans<<endl;
}
是不是有點感覺了
還要多練練題,基礎的思路就是判斷狀態是否可以轉化為二進位制,推導dp方程然後寫就完事
PS:位運算一定要好好記:) (慘痛教訓)
相關文章
- HDU 5816 Hearthstone(狀態壓縮DP+概率)
- hdu--5418Victor and World+狀態壓縮DP
- bzoj4145: [AMPPZ2014]The Prices(狀態壓縮+Dp)
- 狀態壓縮
- 動態規劃——用二進位制表示集合的狀態壓縮DP動態規劃
- 狀壓DP
- 狀壓 dp
- [狀壓dp] 最短Hamilton路徑(模板題+狀壓dp)
- HDU 3006 The Number of set (狀態壓縮)
- 論文閱讀 狀態壓縮
- PDF Squeezer for mac(簡易壓縮工具)Mac
- POJ3279 Fliptile【狀態壓縮+DFS】
- ACM-ICPC 2018 南京賽區網路預賽__E AC Challenge【狀態壓縮+DP】ACM
- 動態規劃中初識狀態壓縮(入門)動態規劃
- POJ 2777 Count Color (線段樹+狀態壓縮)
- 狀壓DP基礎入門
- HDU 1074 Doing Homework(狀壓DP)
- 合理安排(狀壓dp,包括技巧)
- E - Remove Pairs(狀壓dp+博弈論)REMAI
- NOI2001 炮兵陣地(狀壓dp)
- Luogu P1777 幫助 題解 [ 紫 ] [ 線性 dp ] [ 狀壓 dp ]
- 強大且易於使用的壓縮和解壓縮軟體:Keka for MacMac
- 前端狀態管理簡易實現(以vuex為例)前端Vue
- 分組(狀壓dp+技巧:快速列舉子集)
- 影片壓縮技術簡介
- Nginx網路壓縮 CSS壓縮 圖片壓縮 JSON壓縮NginxCSSJSON
- Codeforces 11D A Simple Task 題解 [ 藍 ] [ 狀壓 dp ]
- Keka Mac:高效簡潔的壓縮解壓工具Mac
- Word檔案太大怎麼壓縮,分享壓縮Word的簡單方法
- 怎麼把影片壓縮?實用又簡單的壓縮影片方法
- 簡單好用的js 壓縮工具JS
- 百練4124:海賊王之偉大航路(狀壓DP)
- 檔案壓縮和解壓縮
- Python實現壓縮和解壓縮Python
- JS壓縮方法及批量壓縮JS
- linux下壓縮解壓縮命令Linux
- linux壓縮和解壓縮命令整理Linux
- CF79D Password (差分+狀壓 dp+最短路/bfs)