基本的狀壓DP

2022-02-24 21:12:47 字數 3871 閱讀 2371

給出乙個 \(n\timesm\) 要求棋子不相鄰,求方案數

\(n < 100\)

\(m < 8\)

\(f[i][s] = \sum\)(為零表示不相鄰)

\(s\) 表示當前行中棋子的情況

解析:我們會發現乙個問題,上述式子確實可以保證上下行不相鄰,但是左右呢,對於我這個剛認識狀壓的菜雞來說,很懵逼,答:狀態壓縮的本質:存在乙個維度是在進製級別表達多組狀態,這個維度的列舉時值得我們思考

狀壓維度的列舉十分重要,而在這題中,對於同一行不相鄰的情況我們可以單獨列舉出來,沒有**,但可以口胡

列舉一行中所有可能,做個預處理,用 \(cnt\) 記錄即可,在轉移方程時就可以按照 \(cnt\) 來列舉,且每個狀態都是當前行的合法狀態,對於航與航之間的處理,就出現了上述的轉移方程式,

for (int i = 1; i <= (m << 1); i++)

if(legitimate) tmp[++cnt] = a[i];//當前行合法狀態

for (int i = 1; i <= n; i++)

for (int s = 1; j <= cnt; j++)

}

\(d[i][j][s] = \sum\)

cnt[s] 表示 s 中有多少個一,\(s_2\) 表示上一行的狀態

\((s<<1|s>>1|s)\&s_2 = 0\) 表示斜方向不衝突

保證這一行沒有相鄰的,預處理

預處理: 列舉該行所有情況,並記錄用的國王數,是否衝突和上邊方法一樣

int n, k, f[11][160][160], num[160], cnt, s[162], ans;

void pre()}}

for (int i=1;i<=cnt;i++)

ans += f[n][i][k];

cout<(s&(1<\(i\) 位是不是 \(1\)

s=s|(1<\(i\) 為設定成 \(1\)

s=s&(~(1<\(i\) 位設定成 \(0\)

s^(1<\(i\) 為的值取反

s=s&(s-1)把乙個數字 \(s\) 二進位制下最靠右的第乙個 \(1\) 去掉

for (s0=s;s0;s0=(s0-1)&s)依次列舉 \(s\) 的子集

for (int s=0;s<=mx;s++)

for (int s0=s;s0;s0=(s0-1)&s)

我們列舉一下

當 \(s=1010\) 此時 \(s_0=1010\)

減一得 \(s_0=1001\)

與\(s\) 與得 \(s_0=1000\)

減一得 \(s_0=0111\)

與\(s\) 與得 \(s_0=0010\)

減一得 \(s_0=0001\)

與\(s\) 與得 \(s_0=0000\)

這樣我們得到了集合 \(s\) 的所有子集 \(s_0\) 即\(\\),特別神

那麼時間複雜度是什麼

\(o(3^n)\)

推導:對於有著 \(k\) 個 \(1\) 的二進位制數字,列舉子集需要的時間複雜度為 \(2^k\) , 擁有 \(k\) 個 \(1\) 的數字的數量用組合數學可知:\(\dbinom\)

那麼總的時間複雜度為:\(\sum_^nc(n,i)\times2^k\)

這裡給出二項式定理

\((x+y)^n=\sum_^n\dbinom\times x^\times y^k\)

我們將這裡的 \(x\) 預設為 \(1\), 則 \(y\) 就等於 \(2\)

那麼時間複雜度就為 \((1+3)^n=o(3^n)\)

子集類問題,大概思路就是

預處理出每種情況的限制條件

在轉移時,是先列舉維度狀態,在列舉維度狀態的子集,將維度狀態分成子集合並的形式,這樣好理解了,和普通的dp斷點是差不多的。

這題的轉移方程

\(f[i]=min\\)

條件是\(w[i\ xor\ j] <= a\)

int a,b,t[1<>a>>b;

int mx=(1<>t[i]>>w[i];

for (int i=0;i<=mx;i++)

}memset (f,0x3f,sizeof(f));

f[0]=0;

for (int i=0;i<=mx;i++)

}cout<> (i - 1)) & 1) }}

scanf("%d", &n);

for(int i = 1 ; i <= n ; ++ i)

}printf("%lld\n", (ans % mod + mod) % mod);

}

給出拓撲圖,求不同的拓撲序的方案數

$d[s] $ 表示前s集合的點中都已經在拓撲序中的方案數,轉移考慮一下下乙個點選什麼,下乙個選的點藥滿足他在s中的點選完後的入讀0,

木聽懂

放鬆題

1 表示這乙個豎著的骨牌的上半部分,即下半部分需要接

0 表示下面不需要接

1的話必須為0

0的話可以為1或0

預處理兩個狀態是否可以轉移,這樣可\(o(1)\) 轉移

拋物線的數量為n^2

不同 狀態的轉移不同,決策是列舉拋物線,

重複計算優化,看課件(沒寫)

強制編號最小的則就會固定兩點,則列舉另乙個點n次

優化了乙個n

3次方靠譜,列舉子集

不知道具體是誰的腳,進而不止到和誰交換腳

!對於乙個可能合法的配置,那麼他們一定保證排序 排序以後他們之間的限制小於 c ,可以不斷交換鹿角,得到相鄰的奇偶對,(判斷是否存在合法解)

合法解判斷的上限: n - 1

因為貪心的強制滿足鹿的交換,那麼最多 n - 1 次

希望把鹿分成組,每組內交換龍角的條件,之前是將所有的鹿角交換,這樣就會快許多。

選擇盡量的多的合法組使得組合成滿足條件全集 s

\[dp[i]= max\

\]\(dp[i]\) 表示 集合為 i 的並起來是乙個合法集合最小數

從任意點出發走過

兩位壓成四位,代替三維

給出1-n排列的其中一種最長上公升子串行,求原序列可能的種樹

n <= 15

tsp問題

20 一般是 2^n, 2^n *n

n <= 16 列舉子集

還有乙個沒寫

選出不相交集合合併起來形成全集,而且總權值最大或最小, 最大方案數

可以列舉子集來做,分成子結構

注意:列舉子集如果控制最小的選的話,那麼可以減少一點的重複的計算。(憤怒的小鳥)

(。。)實際上不需要所有列舉,以內拋物線不一定經過所有的子集,因此我們列舉的是拋物線的個數。

轉移 dp基本就是這樣

特點 n = 16 \(3^n\)

tsp問題,對三進製狀態的初探

狀壓dp 玉公尺田 狀壓dp

相關 強相關 327.玉公尺田 狀壓dp 小國王 狀壓dp 是井字形,本題是十字形。思路 狀態計算 時間複雜度 n 2 n 2n o n 22n 12 2 24n 2 n 2 n o n2 12 2 n 2n 2 n o n22n 12 224 看著妥妥超時,但是裡面合法狀態很少 依舊可以過 在此,...

狀壓dp小記

鋪磚 題意 現有nm的一塊地板,需要用12的磚塊去鋪滿,中間不能留有空隙。問這樣方案有多少種 include using namespace std typedef long long ll const int maxn 1 11 int n,m,state ll dp 15 maxn s1表示本行...

狀壓dp學習

p2704 炮兵陣地 1038 裁玻璃 狀壓dp是一種非常暴力的做法,列舉所有可能的狀態,找到要求的最佳狀態,與一般dp不同,前一項與後一項有一些複雜的狀態關係。dp的引數 物品個數 行數等 當前狀態 上乙個狀態 將abc的有無表示成乙個8個狀態,列舉所有組,列舉上乙個狀態,得到當前狀態的最優解 i...