ACM-11月19日周日周末训练心得

来源:互联网 发布:大数据人才需求 编辑:程序博客网 时间:2024/05/29 18:27

    这周看了树形DP的一些博客,比如一道compuer的题目要去求树上每个点的最远距离是多少,这题一直被称为树形dp的经典是有它的道理的,因为树dp就是把dp放到树上做了,一般是从上到下或从下到上(利用回溯)的移转状态而这题很合适的需要两次dfs。对于<u,v>(有向),dp[u][0]表示在u的子树下u的最远距离是多少dp[u][1]表示在u的子树(和dp[u][0]不是同一孩子)u的次远距离是多少dp[u][2]表示通过u的父亲能走的最远距离是多少第一次从下到上,对于<u,v>(有向),状态转移显然是 dp[u][0] = dp[v][0]+w[i];所以要先算出dp[v][0]才能知道dp[u][0]。故是从下往上。第二次从上往下,其实就是再遍历一边图,把dp[v][2]算出来,显然:dp[v][2] = max(dp[u][2],dp[v][0]+w[i]==dp[u][0]?dp[u][1]:dp[u][0]) + w[i];要算dp[v][2],要先算dp[u][0],所以从上往下。最后的答案就是 max(dp[u][0],dp[u][2])。

void dfs1(int u,int v) //每个节点子树下的最大和次大  {      for(int i=head[u];i!=-1;i=edge[i].next)      {          int v=edge[i].v;          dfs1(v,u);          int w=edge[i].w;          int temp = dp[v][0] + w;          if(temp >= dp[u][0])          {              dp[u][1]=dp[u][0];              dp[u][0] = temp;          }          else if(temp > dp[u][1])              dp[u][1] = temp;      }   }   void dfs2(int u,int v)  {      for(int i=head[u];i!=-1;i=edge[i].next)      {          int v=edge[i].v;          if(dp[u][0] == dp[v][0] + edge[i].w)          {              dp[v][2] = max(dp[u][2],dp[u][1]) + edge[i].w;          }          else          {              dp[v][2] = max(dp[u][2],dp[u][0]) + edge[i].w;          }          dfs2(v,u);      }  }
    对于HDU1520,给一棵树,选最多的结点使得选择的结点不存在直接的父子关系,很容易想到一个结点有两个状态:选或者不选
,所以自然地想到状态dp[u][0/1]表示u子树内的最佳答案,u的状态为选或者不选,初始化自然是叶子结点dp[u][0]=0,dp[u][1]=w[u],转移则可以考虑依次考虑,u不选的时候:u的儿子可以任意选或者不选,所以dp[u][0]+=max(dp[v][0],dp[v][1]),u选的时候:u的儿子必定不能选,所以dp[u][1]+=dp[v][0]   然后dp[u][1]+=w[u]表示加上u这个点,答案自然就是max(dp[rt][0],dp[rt][1])了。


原创粉丝点击