题目连接
看起来彷佛跟最小点覆盖有点像。但区别在于:
最小点覆盖要求全部边在其中,而本题要求全部点在其中。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; }