【狀壓dp】Y
阿新 • • 發佈:2020-08-13
題意
一個圖中,每條邊的邊權是0或1,求出長度為d的不同的路徑數(路徑即經過邊的01串)。
思路
考慮折半,最後把d分成2部分的01串組合起來。
設dp[i]為狀態為i時的終點點集,f[i]為狀態為i時的起點點集(2個bitset)。
列舉2段01串,判斷是否存在中間點可以轉移,累加答案。
程式碼
#include <cstdio> #include <bitset> const int MAXS = 1 << 11; std::bitset<91> dp[MAXS], f[MAXS], g0[91], g1[91]; int n, m, d, d1, d2, ans; int main() { scanf("%d %d %d", &n, &m, &d); for (int i = 1, u, v, c; i <= m; i++) { scanf("%d %d %d", &u, &v, &c); c ? g1[u][v] = g1[v][u] = 1 : g0[u][v] = g0[v][u] = 1; } d2 = d >> 1; d1 = d - d2; for (int u = n; u; u--) { for (int i = 0; i < MAXS; i++) dp[i].reset(); dp[1][u] = 1;//在前面放1表示長度為多少的狀態 for (int i = 1; i < 1 << d1; i++) for (int j = 1; j <= n; j++) if (dp[i][j]) { dp[i << 1] |= g0[j]; dp[i << 1 | 1] |= g1[j]; } for (int i = 0; i < 1 << d1; i++) f[i][u] = dp[1 << d1 | i].any(); } for (int i = 0; i < 1 << d1; i++) for (int j = 0; j < 1 << d2; j++) if ((dp[1 << d2 | j] & f[i]).any()) ans++; printf("%d", ans); }