Wannafly #1 Treepath(树形DP)

来源:互联网 发布:苏州软件测试工资待遇 编辑:程序博客网 时间:2024/04/28 05:50

problem

给定一棵n个点的树,问其中有多少条长度为偶数的路径。路径的长度为经过的边的条数。x到y与y到x被视为同一条路径。路径的起点与终点不能相同。

Input

第一行一个数n表示点的个数;
接下来n-1行,每行两个整数x,y表示边;
保证输入数据形成一棵树;
1<=n<=100000

Output

一行一个整数表示答案。

Sample Input

3
1 2
1 3

Sample Output

1


思路

考虑tree DP,dp1【】数组表示以当前结点为根的子树中所有到根的路径长度为奇数的结点数
dp2【】数组表示以当前结点为根的子树中所有到根的路径长度为偶数的结点数。就有“父奇为儿偶,父偶为儿奇”
进入每个结点时,初始化为dp1[rt]=0,dp2[rt]=1;
就是说,“零距离”记为1个,这样在计数时,比如叶子节点的父节点,奇数就加上偶数(0+1=1),偶数就加上奇数(0+0=0),符合。

另外,最关键的一点在于 ans+=dp1[rt]*dp2[tt]+dp2[rt]*dp1[tt];
就是说,对当前这个根节点,有一个它的子树到他的奇  另外一个子树的奇(奇+奇=偶)(或者说是已经合并的,实际上这就是一个合并信息到根的过程),和偶 偶(偶+偶=偶),就是ans要加的值。


核心代码为

void dfs(int rt,int f){    dp1[rt]=0;    dp2[rt]=1;    for(int i=head[rt];i!=-1;i=edges[i].to){        int tt=edges[i].from;        if(tt==f) continue;        dfs(tt,rt);        ans+=dp1[rt]*dp2[tt]+dp2[rt]*dp1[tt];        dp1[rt]+=dp2[tt];//父奇为儿偶        dp2[rt]+=dp1[tt];//父偶为儿奇    }}


代码示例

#include<iostream>#include<string.h>#include<cstdio>using namespace std;const int maxn=100010;int head[maxn<<1];int tot,n;//tot辅助存边(边集数组转邻接表),n为结点数struct Edge{    int from,to;}edges[maxn<<1];void init(){    memset(head,-1,sizeof(head));    tot=0;}void add_edge(int u,int v){    edges[tot].from=v;    edges[tot].to=head[u];    head[u]=tot++;}int dp1[maxn],dp2[maxn];//1为奇路径方案数,2为偶路径方案数long long ans=0;//答案void dfs(int rt,int f){    dp1[rt]=0;    dp2[rt]=1;    for(int i=head[rt];i!=-1;i=edges[i].to){        int tt=edges[i].from;        if(tt==f) continue;        dfs(tt,rt);        ans+=dp1[rt]*dp2[tt]+dp2[rt]*dp1[tt];        dp1[rt]+=dp2[tt];        dp2[rt]+=dp1[tt];    }}int main(){    //ios::sync_with_stdio(false);        int u,v;        scanf("%d",&n);        init();        for(int i=1;i<n;++i){            scanf("%d %d",&u,&v);            add_edge(u,v);            add_edge(v,u);        }        dfs(1,-1);        cout<<ans<<endl;    return 0;}
原创粉丝点击