參考部落格:牛客網 wannafly挑戰賽17 c-簡單環 狀壓dp
題目描述
給定一張n個點m條邊的無向圖,求出圖中所有簡單環的數量。(簡單環:簡單環又稱簡單迴路,圖的頂點序列中,除了第乙個頂點和最後乙個頂點相同外,其餘頂點不重複出現的迴路叫簡單迴路。或者說,若通路或迴路不重複地包含相同的邊,則它是簡單的)
輸入描述:
第一行三個數n m k (k在輸出描述中提到)
接下來m行每行兩個數u,v表示u到v之間存在一條邊(無重邊)
輸出描述:
輸出k行每行1個整數
第i個數表示長度%k==i-1的簡單環的數量(對998244353取模)
(只記錄長度大於2的簡單環的數量)
輸入4 6 3
1 22 3
3 44 1
2 41 3輸出4
30備註:n<=20
m<=n*(n-1)/2
k<=n
思路把路徑轉化為二進位制狀態,設定乙個陣列 f[i][j] 表示路徑終點為 j ,二進位制下狀態為i的數目,為了避免重複,可以把 i 最小位的 1 設為起點,列舉狀態和終點,若終點到起點有直接連線則為答案。最後每條環仍會重複計算兩次,需要求除法逆元去重。
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
// n 個點,m 條邊,k 行輸出
int n, m, k;
//記錄能走的路
bool vis[21]
[21];
//f[i][j]儲存路徑終點為 j,二進位制下狀態為 i 的個數
int f[
1<<21]
[21];
//ans 記錄最後的結果,只用 0 ~ k-1
//len 記錄不同 i 長度環的個數
int ans[21]
, len[41]
;const
int mod =
998244353
;//返回二進位制下最低位 1 的位置
intlowbit
(int x)
intmain()
}//初始化 f
for(
int i =
1; i <= n; i++
)for
(int i =
2; i <
1<<
(n +1)
; i +=2
)}// cout<<"i: "(int j =
1; j <= n; j++
)//從 s+1 開始列舉,避免重複計算路徑
for(
int k = s +
1; k <= n; k++)}
}}}//只記錄長度大於 2 的簡單環的數量
for(
int i =
3; i <= n; i++
)//每個環仍舊會被重複計算兩次
for(
int i =
0; i < k; i++
)return0;
}
狀壓DP(超詳細!!!)
狀態壓縮動態規劃,就是我們俗稱的狀壓dp,是利用計算機二進位制的性質來描述狀態的一種dp方式。很多棋盤問題都運用到了狀壓,同時,狀壓也很經常和bfs及dp連用。狀壓dp其實就是將狀態壓縮成2進製來儲存 其特徵就是看起來有點像搜尋,每個格仔的狀態只有1或0 是另一類非常典型的動態規劃 舉個例子 有乙個...
hdoj 3555 數字dp,詳細注釋
數字dp可以解決類似這樣一道給你上下界,求裡面符合要求的數字,暴力肯定超時的.下面給出帶注釋的 include includetypedef long long ll using namespace std ll dp 20 2 ll dight 20 ll dfs ll len,bool if4,...
簡單的期望 狀壓dp
dp定義真的神,直接的想法是 f x maxn 為第 x 個操作,狀態 maxn maxn 1 200,好像沒有暴力分高 實際上我們可以這樣定義 f x maxn len 0 1 表示後八位 maxn 第九位0 1,第九位之後連續長度為 j 概率 為什麼這樣定義 實際上質因數分解後2的次數就是後面0...