Y(类树形DP)
Y
题意:给你一棵树,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有些像,果然要学着举一反三啊啊啊啊啊啊~~~