[关闭]
@Acqua 2019-01-25T01:21:33.000000Z 字数 1647 阅读 1164

Vijos1144 小胖守皇宫(Jan. 25th, 2019) 树形DP

动态规划 特殊技巧

题目来源

题意

给定一棵有个结点的树,选取一个结点就能够支配与其直接相连的所有结点,求支配该树所有结点所需要选取的最小结点数。

思路

启发式思维,
使用图论模板,树形
表示结点被其父结点支配、被其自身支配、被其子结点支配。
如果结点被其父结点支配,就不可支配其子结点
结点只能由其自身或其子结点支配。

如果结点被自己支配,其子结点都被父结点支配,但也可以被自己或子结点支配。

如果结点被其子结点支配,则必定要至少一个自身支配,其余的可以由自己或子结点支配。为了保证强制选取且答案最优,用记录差值最小的[1]

代码

  1. // La Pluie
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. const int N=1505;
  8. struct edge{
  9. int v,next;
  10. }e[N<<1];
  11. int n,head[N],dp[N][3],k=1;
  12. void adde(int u,int v){
  13. e[k]=(edge){v,head[u]};
  14. head[u]=k++;
  15. }
  16. void dfs(int u,int f){
  17. int mn=2147483647;
  18. for(int i=head[u];i!=-1;i=e[i].next){
  19. int v=e[i].v;
  20. if(v==f) continue;
  21. dfs(v,u);
  22. dp[u][0]+=min(dp[v][1],dp[v][2]);
  23. dp[u][1]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
  24. mn=min(mn,dp[v][1]-min(dp[v][1],dp[v][2]));
  25. dp[u][2]+=min(dp[v][1],dp[v][2]);
  26. }
  27. dp[u][2]+=mn;
  28. }
  29. int main(){
  30. memset(head,-1,sizeof(head));
  31. scanf("%d",&n);
  32. for(int i=1;i<=n;i++){
  33. int u,v,ctrl;
  34. scanf("%d",&u);
  35. scanf("%d%d",&dp[u][0],&ctrl);
  36. for(int j=1;j<=ctrl;j++){
  37. scanf("%d",&v);
  38. adde(u,v);adde(v,u);
  39. }
  40. }
  41. dfs(1,0);
  42. printf("%d\n",min(dp[1][1],dp[1][2]));
  43. return 0;
  44. }

[1] 证明:该式等价于:如果,那么该式代表用替换掉所产生的额外花费;反之,该式结果为,即在这一步时就不可能选择到该,也就没有因为替换而产生的额外花费。因为第二种情况在计算时已经选取了至少,所以保证了结果的性质正确。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注