看到題目之後——果斷樹形dp啊!!
但是怎麼樹形dp啊qwq。。。。開始想的是\(dp[i][0/1]\)來表示i節點擊不選擇。
那麼狀態轉移方程:
\(dp[i][0]=\sum_^{}dp[v][1]\)
\(dp[i][1]=val[i]+\sum_min(dp[v][0],dp[v][1])\)
然後如果所有小的都是dp[v][0],找乙個最小的dp[v][1]加上,然後減去原先對應加上的。
會被這樣一組簡單的資料hack掉:
91 1 1 2
2 5 3 3 4 5
3 100 1 6
4 100 1 7
5 100 2 8 9
6 1 0
7 1 0
8 1 0
9 1 0
為什麼呢?是因為我們沒有考慮用父親節點控制該節點的情況。
所以正確的狀態設計應該是這樣的:
\(dp[i][0]\)表示節點\(i\)至少被父親節點控制。
\(dp[i][1]\)表示節點\(i\)至少被子節點控制。
\(dp[i][2]\)表示節點\(i\)至少被自己控制。
\(dp[i][0]=\sum min(dp[son(i)][1],dp[son(i)][2])\)
\(dp[i][1]=\sum min(dp[son(i)][1],dp[son(i)][2])+dp[son(i)][2]\)
(其中至少有乙個是1)
\(dp[i][2]=\sum min(dp[son(i)][0],dp[son(i)][1],dp[son(i)][2])+val[i]\)
**如下:
#include#include#include#include#include#define maxn 2010
using namespace std;
struct edgeedge[maxn<<1];
int edge_number,n,ans=2147483647;
int val[maxn],head[maxn];
long long dp[maxn][3];
void add(int from,int to)
inline void search(int now,int fa)
dp[now][0]=sum;
dp[now][1]=2147483647;
for(int i=head[now];i;i=edge[i].nxt)
return;
}int main()
}memset(dp,0x3f,sizeof(dp));
search(1,0);
printf("%lld\n",min(dp[1][1],dp[1][2]));
return 0;
}
SDOI 2006 保安站崗
洛谷傳送門 五一來臨,某地下超市為了便於疏通和指揮密集的人員和車輛,以免造成超市內的混亂和擁擠,準備臨時從外單位呼叫部分保安來維持交通秩序。已知整個地下超市的所有通道呈一棵樹的形狀 某些通道之間可以互相望見。總經理要求所有通道的每個端點 樹的頂點 都要有人全天候看守,在不同的通道端點安排保安所需的費...
SDOI 2006 保安站崗
給出一棵 n 個節點以 1 為根的樹,乙個節點的覆蓋半徑是 1 點有點權 val x 選擇一些點,使得點權和最小,同時每個節點要麼被選擇要麼被周圍的點覆蓋。樹形dp 的討論。注意到覆蓋有可能呈現出兩層都沒有選點的情況 下面被子樹覆蓋,上面被父節點覆蓋 所以狀態設計要注意。設 f i 0 1 2 表示...
SDOI2006 保安站崗
傳送門 一道很好的樹型dp。一開始我的狀態選擇是用dp i 0 表示以i為根節點,不選擇i的最小花費,dp i 1 表示以i為根節點,選擇i的最小花費。但是這樣我發現無法轉移,因為你不能保證選或者不選的正確性 問題在於狀態設少了。乙個點有三種狀況,乙個是本身站有保安,乙個是被自己的子節點控制,乙個未...