狀態壓縮好題。下面我們來一一分析一下這道題的總體想法。
容易發現,\(n\leq12\)暗示這道題時間複雜度為指數級別的。
由於題目表明
兩個已經被挖掘過的寶藏屋之間的道路無需再開發。所以,我們開發的路徑構成的只能是一棵樹,不能是有環的圖。
因此,我們可以將題目抽象成:給定一張有\(n\)個點的圖,求出一棵生成樹(根節點任意)使 \(\sum_ dep_u\times w(u,fa_u)\)最小。
由於\(n\)很小,不難想到可以使用狀態壓縮。
我最開始的想法是:列舉根節點\(root\),並定義以當前的根為根節點的狀態:\(d(i,j,s)\)代表當前葉子結點\(j\)距\(root\)距離為\(i\)時,正處理的點集是\(s\)的最小值。
那麼\(i\geq2\)時有如下轉移:\(dp(i,j,s)=min(dp(i-1,k,s\setminus\)+i\times d(i,k))\)。
而\(j=1\)有:\(dp(i,j,s)=min(dp(x,k,s\setminus\)+d(j,root))\)。
初始化:讓\(dp(0,root,0)=0\),其餘\(\infty\)。
這樣的做法效率大約是:\(o(n^42^)\),實際測試中所有的狀態是跑不滿的,故這種做法是可以通過本題目的時間限制的。
我們注意到剛剛那個轉移是相當混亂的,並且它會重複計算狀態值。
我們上述做法本質上是利用葉子結點向上逆推推的過程。那麼,我們是否可以反過來想——從乙個結點向它的子結點擴充套件,考慮剩下的子結點集合的代價。
根據此,我們來重新定義之前的狀態表示:
\(dp(i,j,s)\)代表距離根節點距離\(i\)考慮到的當前結點為\(j\),從\(j\)開始「挖」的點集為\(s\)的最小代價和。換句話來講,我們只考慮以\(j\)為根的子樹的代價。
那麼有:\(dp(i,j,s)=min(dp(i+1,k,s'\setminus\)+dp(i,j,s\setminus)+d(j,k))\),這裡面的\(s'\)代表的是\(s\)中的子集,而k是s『中的元素。
不難觀察到,方程類似於樹形dp中子樹合併該重要思想。事實上,我們利用它解決樹形依賴關係的一類問題(揹包九講)。
初始化,我們讓\(dp(i,j,0)=0\),其餘正無窮,最終答案為\(min(dp(0,i,u\setminus\))\)。時間複雜度為\(o(n^32^n)\),具體計算過於複雜,在此不展開。
在實現的過程中,為優化常數,我們可以預處理出所有狀態下的元素個數、最小元素下標,以及將所有的點的下標平移。
另外,要注意邊界條件。
#include#include#include#include#define re register
#define clr(x, y) memset(x,y,sizeof x)
#define for(i, x, y) for(re int i=x;i<=y;++i)
#define rof(i, x, y) for(re int i=x;i>=y;--i)
using namespace std;
const int n = 13, s = 1 << n, inf = 1e9 + 5;
typedef long long ll;
template void read(t &x)
int n, m, t, siz[s] = {}, tt[s] = {};
ll ans = inf, d[n][n], dp[n][n][s];
int main()
ll u, v, w;
for(i, 1, m)
for(i, 1, t) siz[i] = siz[i & (i - 1)] + 1;
for(int i = 0; i < n; ++ i) tt[1 << i] = i;
for(i, 1, t) tt[i] = tt[i & (-i)];
clr(dp, 0x3f);
for(int i = 0; i < n; ++ i)
for(int j = 0; j < n; ++ j)
dp[i][j][0] = 0;
for(int i = n - 2; i >= 0; -- i)
}} }
for(int i = 0; i < n; ++ i) ans = min(ans, dp[0][i][t ^ (1 << i)]);
printf("%lld\n", ans);
return 0;
}
總結:
當資料規模很小的時候,可以考慮狀態壓縮;
在考慮樹上問題時往往從根節點開始考慮(像倍增一類的題目是從自己點開始考慮);
NOIP 2017 提高組 寶藏
傳送門 參與考古挖掘的小明得到了乙份藏寶圖,藏寶圖上標出了 n nn 個深埋在地下的寶藏屋,也給出了這 n nn 個寶藏屋之間可供開發的 m mm 條道路和它們的長度。小明決心親自前往挖掘所有寶藏屋中的寶藏。但是,每個寶藏屋距離地面都很遠,也就是說,從地面打通一條到某個寶藏屋的道路是很困難的,而開發...
NOIP2017提高組正式賽 寶藏
description 參與考古挖掘的小明得到了乙份藏寶圖,藏寶圖上標出了 n 個深埋在地下的寶藏屋,也給出了這 n 個寶藏屋之間可供開發的 m 條道路和它們的長度。小明決心親自前往挖掘所有寶藏屋中的寶藏。但是,每個寶藏屋距離地面都很遠,也就是說,從地面打通一條到某個寶藏屋的道路是很困難的,而開發寶...
Noip2017提高組 乳酪
noip 2017 提高組 不怎麼難啦 思路如下 首先先寫乙個函式判斷兩個洞是否相連,即兩洞之間距離是否小於等於球直徑 注意是直徑 struct dong dong p 1001 bool pd dong a,dong b 第二個難點在於如何判斷是否可以穿過乳酪,對此我們可以模擬老鼠鑽洞 run函式...