題目連接
看起來彷佛跟最小點覆蓋有點像。但區別在於:
最小點覆蓋要求全部邊在其中,而本題要求全部點在其中。html
即:一個點不選時,它的兒子不必定須要全選。
畫圖理解:node
對於這樣一幅圖,本題中能夠這樣選擇:
:
將相鄰的點
覆蓋,而
將相鄰的點
覆蓋,所以全部點都被覆蓋了。
那麼就必須修改狀態了。web
考慮對於一個點,若是它被覆蓋了,只有三種可能:app
所以咱們設計狀態:svg
那麼如何轉移呢?spa
本身被標記時,兒子的3種狀態都是合法的,所以有:
設計
而父親被標記時,兒子不能被父親標記了,只能本身標記或者被兒子的兒子標記。
code
被兒子標記的狀況就複雜一些。首先,被兒子標記時,全部兒子確定沒法被父親標記,所以首先有:
orm
可是至少須要有一個兒子標記本身,才能讓當前節點被兒子控制。若是一遍下來都沒有選取 的狀況怎麼辦呢?xml
咱們考慮一個兒子,若是它被兒子標記更優,咱們卻強制它標記本身,那麼代價就是 。
那麼咱們在遍歷兒子時記錄,看是否有兒子選取了控制本身,若是沒有的話,就選擇代價最小的那個兒子強制標記它便可。
實現彷佛沒有太多坑點。
但要注意:當一個點是葉子結點時,
即被兒子標記的代價必定是
,在代碼中我直接並在了最後的處理中。能夠感覺一下。
另外就是這題的數據問題,雖說題面是嚴格父親對應兒子,但我建單向邊死活過不了第三個點,改爲雙向邊後AC。
最後答案,根節點不能被父親控制。
#include <cstdio> #include <cstring> using namespace std; template<typename T> void read(T &r) { static char c; r=0; for(c=getchar();c>'9'||c<'0';c=getchar()); for(;c>='0'&&c<='9';r=(r<<1)+(r<<3)+(c^48),c=getchar()); } struct node { int to, next; node() {} node(const int &_to, const int &_next) : to(_to), next(_next) {} } lines[3002]; int head[1501]; void add(const int &x, const int &y) { static int tot = 0; lines[++tot] = node(y, head[x]), head[x] = tot; } template<typename T> inline T min(const T &a,const T &b){return a<b?a:b;} template<typename T> inline T min(const T &a,const T &b,const T &c){return min(min(a,b),c);} template<typename T> inline T max(const T &a,const T &b){return a>b?a:b;} int n; int w[1501]; int dp[1501][3]; //dp[i][0] 本身控制 //dp[i][1] 父親控制 //dp[i][2] 兒子控制 void dfs(int now,int fa) { int v,minp = 999999999; bool flag = true;//標記是否強制有一個兒子控制本身 dp[now][0] = w[now]; for(int p = head[now];p;p=lines[p].next) { v = lines[p].to; if(v == fa) continue; dfs(v,now); dp[now][0] += min(dp[v][2],dp[v][1],dp[v][0]); dp[now][1] += min(dp[v][0],dp[v][2]); if(dp[v][0] <= dp[v][2]) { //此時能夠直接選擇這個兒子控制本身了 flag = false; dp[now][2] += dp[v][0]; } else { dp[now][2] += dp[v][2]; minp = min(minp,dp[v][0] - dp[v][2]); } } if(flag) dp[now][2] += minp; } int main() { read(n); int m,u,x; for(int i = 1;i<=n;++i) { read(u); read(w[u]); read(m); while(m--) { read(x); add(u,x); add(x,u);//竟然要雙向邊?! } } dfs(1,0); printf("%d",min(dp[1][0],dp[1][2])); return 0; }