HDU 3534 Tree(经典树形dp)

题意:在一棵树上找最长路径,和他出现的个数。

思路:有做过poj1985(求树直径)的基础,我们知道我们一遍dfs可以得到dp[i]表示i点为根的子树到叶子的最长距离,次长距离,同时我们还可以记载他们出现的数量。

我们可以先简单的分析,定义dp[i][0],dp[i][1]i点为根到叶子的最长,次长距离,dp[i][2],dp[i][3],表示他们出现的次数。如果对于某个节点,最长次长不相等(dp[i][0]!=dp[i][1]),那么经过这点的最长路径的个数就是他们乘积(dp[i][2]*dp[i][3]),反之,可以在转移过程中求得如果次长和最长相等的个数。

分析:转移过程具体看代码,思路很清晰。(懒)

#include
using namespace std;
const int maxn=1010;
template//N点的个数,M边的个数
struct Graph
{
    int top;
    struct Vertex{
        int head;
    }V[N];
    struct Edge{
        int v,next,w;
    }E[M];
    void init(){
        memset(V,-1,sizeof(V));
        top = 0;
    }
    void add_edge(int u,int v,int w){
        E[top].v = v;
        E[top].next = V[u].head;
        E[top].w=w;
        V[u].head = top++;
    }
};
const int N=1000000+10;
Graph g;
int dp[N][5];
void dfs(int u,int f){
  dp[u][2]=1;dp[u][3]=1;
  for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
    int v=g.E[i].v,w=g.E[i].w;
    if(v==f) continue;
    dfs(v,u);
    if(dp[v][0]+w==dp[u][0]){//如果根节点里最长的路径不只一条。
       dp[u][4]+=(dp[v][2]*dp[u][2]);//更新根到叶子节点里最长和次长相等的情况能组成的最长路径的个数
       dp[u][2]+=dp[v][2];//更新根到叶子节点里最长的个数
    }
    if(dp[v][0]+w==dp[u][1]) dp[u][3]+=dp[v][2];//更新根到叶子次长的个数
    if(dp[v][0]+w>dp[u][0]){//更新根到叶子节点最长边的权值和次数
        swap(dp[u][0],dp[u][1]);
        swap(dp[u][2],dp[u][3]);
        dp[u][0]=dp[v][0]+w;
        dp[u][2]=dp[v][2];
        dp[u][4]=0;
    }
    else if(dp[v][0]+w>dp[u][1]){//更新根到叶子节点次长边的权值和次数
        dp[u][1]=dp[v][0]+w;
        dp[u][3]=dp[v][2];
    }
  }
}

int n;

int main(){
   while(~scanf("%d",&n)){
      g.init();
      for(int i=0;imaxx) maxx=dp[i][0]+dp[i][1];
      }
      int ans=0;
      for(int i=1;i<=n;i++){
        if(dp[i][0]+dp[i][1]==maxx){
            if(dp[i][0]==dp[i][1]) ans+=dp[i][4];
            else ans=dp[i][2]*dp[i][3];
        }
      }
      printf("%d %d\n",maxx,ans);
   }
}


你可能感兴趣的:(动态规划之树形dp)