Y(类树形DP)

Y

 HDU - 4705 

题意:给你一棵树,n个节点n-1条边(双向),树上任意三个点不在一条路径上,统计这样的三点集合有多少种。

思路:

  n个节点中任选3个点的方案数为n*(n-1)*(n-2)/6,从中减去三个点在同一条路径上的种类数即为答案。如何找在同一条路径上的方案数呢,就是以固定某一个点,看看他的一个儿子有几个儿子,儿子的儿子个数加上儿子本身,从这些点中选一个,再从剩余的点中选一个,即可以构成三个点在同一条直线上。所有对于固定的这个点x,方案数为sum[son]*(n-sum[x])

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
vector<int>v[maxn];
int vis[maxn];
int a,b;
ll ans,n,t,son[maxn];
void dfs(int x)
{
    vis[x]=1;
    son[x]=1;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(vis[to])
            continue;
        dfs(to);
        son[x]+=son[to];
        ans+=(n-son[x])*son[to]; 
    }
}
int main()
{
    while(~scanf("%lld",&n))
    {
        ans=0;
        memset(son,0,sizeof(son));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<=n;i++)
            v[i].clear();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            v[a].push_back(b); 
            v[b].push_back(a);
        }
        dfs(1);
        t=(n-1)*n*(n-2)/6;
        printf("%lld\n",t-ans);
    }
}

这个题的思路和hdu2376有些像,果然要学着举一反三啊啊啊啊啊啊~~~

posted @ 2018-11-14 20:01  *starry*  阅读(213)  评论(0编辑  收藏  举报