LuoguP3959 宝藏 题解
思路主要是抄_rqy的,這神仙位運(yùn)算tql,整理一下思路。
題目大意
給定\(n\)個(gè)點(diǎn),\(m\)條有權(quán)邊,從一個(gè)點(diǎn)\(s\)開始挖(任選),形成一個(gè)生成樹(即已經(jīng)挖通的兩個(gè)點(diǎn)間不能連邊),挖一條邊的代價(jià)為邊的長度乘\(s\)到邊的終點(diǎn)的距離,求最小代價(jià)。
\(n \leq 12\)
思路
狀壓dp。
和一般的狀壓dp不一樣,需要進(jìn)行兩層狀壓。
設(shè)\(f[S][d][i]\)為挖開點(diǎn)集\(S\),現(xiàn)在距離起點(diǎn)的距離為\(d\),所在的點(diǎn)為\(i\)的最小代價(jià)。
則\[f[S][d][i] = \min_{S_1\subset S}^{k\in S1} w(i, k)(d+1) + f[S1-\{k\}][d+1][k] + f[S-S1][d][i]\]
其中\(i \notin S, d+|S| \leq n\),因?yàn)楫?dāng)前至少已經(jīng)挖開了\(d\)個(gè)點(diǎn),最多只能挖開\(n-d\)個(gè)點(diǎn)。
初始化:\(f[0][d][i] = 0\)
注意\(S\)從小到大,\(d\)從大到小。
最終結(jié)果就是\[\min_{i=1}^nS[U-\{i\}][0][i]\]
復(fù)雜度
對于整個(gè)圖,分成子集大小是\(1\)到\(n\)的考慮。
\[T(n) = \sum_{i=1}^n C_n^i 2^i = (2+1)^n = 3^n\]
(二項(xiàng)式定理,大小為\(i\)的集合有\(C_n^i\)個(gè),它的子集有\(2^i\)個(gè))
Code
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm> using namespace std; #define File(IO_Filename) freopen(IO_Filename".in", "r", stdin), freopen(IO_Filename".out", "w", stdout) typedef long long ll; template<typename T> inline void in(T &x){char ch; x = 0;while(isspace(ch = getchar()));do x = x * 10 + ch - '0'; while(isdigit(ch = getchar())); } const int N = 13, INF = 0x3f3f3f3f; int w[N][N], pc[1<<N], low[1<<N]; //pc表示集合的元素個(gè)數(shù),low表示集合內(nèi)最小的元素(用來取子集) int f[1<<N][N][N];void wrbin(int x){if(x == 0) return ;wrbin(x >> 1);putchar('0' + (x & 1)); }int main(){// File("3959");int n, m, x, y, wt, tot;in(n); in(m);memset(w, 0x3f, sizeof(w)); memset(f, 0x3f, sizeof(f));for(int i=1; i<=m; i++){in(x); in(y); in(wt); --x; --y;w[x][y] = w[y][x] = min(w[x][y], wt);}tot = 1 << n;for(int i=0; i<tot; i++) pc[i] = pc[i & (i-1)] + 1;for(int i=0; (1 << i) < tot; i++) low[1 << i] = i;for(int i=0; i<tot; i++) low[i] = low[i & (-i)];for(int d=n-2; d>=0; d--)for(int i=0; i<n; ++i)f[0][d][i] = 0;for(int d=n-2; d>=0; --d)for(int i=0; i<n; ++i){for(int S=1; S<tot; ++S) if(pc[S] <= n - d && (S & (1 << i)) == 0) //優(yōu)化for(int S1=S; S1; S1=(S1-1)&S){ //取S的子集S1for(int t=S1, k=low[t]; t; t&=(t-1), k=low[t]){ //取S1的所有元素if(w[i][k] != INF && f[S1-(1<<k)][d+1][k] != INF && f[S-S1][d][i] != INF)f[S][d][i] = min(f[S][d][i],w[i][k] * (d+1) + f[S1-(1 << k)][d+1][k] + f[S-S1][d][i]);}}}int ans = INF;for(int i=0; i<n; i++)ans = min(ans, f[tot-1-(1<<i)][0][i]);printf("%d\n", ans);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/RiverHamster/p/solution-p3959.html
總結(jié)
以上是生活随笔為你收集整理的LuoguP3959 宝藏 题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 体验Windows Azure的Acce
- 下一篇: 用SC命令 添加或删除windows服务