Y
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 3107 Accepted Submission(s): 918
Problem Description
Sample Input
4 1 2 1 3 1 4
Sample Output
1
Hint
1. The only set is {2,3,4}. 2. Please use #pragma comment(linker, "/STACK:16777216")
Source
2013 Multi-University Training Contest 10
Recommend
zhuyuanchen520
题意:求树中不在一条线上的3个点的种数。
按照题意直接去求显然不好做,可以用总数减去树中在一条线上的3个点的种数,剩下的就是题中所求。
注意,只要三个点可以连起来就算作一种情况,即中间可以有其他点,边是双向的。
对于其中一种情况 A--B--C 我们选取中间点B点为参考点,C是B的儿子节点,A是除了B和B的儿子节点以外的点。
那么对于这种情况,ans=n-son[B])*son[B] 所以我们只需要dfs遍历即可求出树中在一条线上的3个点的种数,而总数直接用组合数求即可。
#include"bits/stdc++.h"
using namespace std;
vector<long long>vt[100004];
long long son[100004];
bool vis[100004];
long long ans;
long long n;
void dfs(long long u)
{
vis[u]=1;
for(int i=0;i<vt[u].size();i++)
{
long long t=vt[u][i];
if(!vis[t])
{
dfs(t);
son[u]+=son[t];
ans+=(son[t])*(n-son[u]);
}
}
}
int main()
{
while(~scanf("%lld",&n))
{
//memset(son,1,sizeof(son));
memset(vis,0,sizeof(vis));
ans=0;
for(int i=0;i<=n;i++)
{
vt[i].clear();
son[i]=1;
}
long long u,v;
for(int i=0;i<n-1;i++)
{
scanf("%lld%lld",&u,&v);
vt[u].push_back(v);
vt[v].push_back(u);
}
dfs(1);
printf("%lld\n",n*(n-1)*(n-2)/6-ans);
}
}