树形DP(简单题)(Y HDU4705)

题意:给出一个n个节点的树形图,统计{A,B,C}的数量,其中ABC分别是树上三个不同的节点,并且这三个节点不能被一条路径覆盖

分析:对于下图


进行dfs深搜统计,num[u]统计回溯到当前节点u,并以u为根节点的子树节点个数,当回溯点到<2,4>不存在,当回溯到<2,5>时可以从{4}中和{5}中分别选择一个然后在选择4到5路径之外的其他任意一点此时ans+=(num[2]-1)*num[5]*(8-num[2]-num[5])=5;当回溯到<2,6>的时候,num[2]={4,5,2};num[6]={6};然后分别从这两个集合中分别选一个元素然后再之外选择一个ans+=(num[2]-1)*num[6]*(8-num[2]-num[6])=5+2*1*4.......最后的ans=18,这种统计方法不会有重复的数据;

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"queue"
#include"algorithm"
#include"string.h"
#include"string"
#include"math.h"
#include"vector"
#include"stack"
#include"map"
#define eps 1e-4
#define inf 10000000
#define M 100009
#define PI acos(-1.0)
using namespace std;
struct node
{
    int u,v,next;
}edge[M*2];
int t,head[M],degree[M];
__int64 ans,num[M],n;
void init()
{
    t=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[t].u=u;
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void dfs(int u,int f)
{
    num[u]=1;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)continue;
        dfs(v,u);
        ans+=(num[u]-1)*num[v]*(n-num[u]-num[v]);
        num[u]+=num[v];
    }
}
int main()
{
    int i,a,b;
    while(scanf("%I64d",&n)!=-1)
    {
        init();
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        ans=0;
        dfs(1,-1);
        printf("%I64d
",ans);
    }
}


原文地址:https://www.cnblogs.com/mypsq/p/4348109.html