Problem Description
Sample Input
4 1 2 1 3 1 4
Sample Output
1Hint1. The only set is {2,3,4}. 2. Please use #pragma comment(linker, "/STACK:16777216")
题意: 有一颗树, 选出3个点。 不在同一条路径上的集合数。
思路: DFS
间接法。
总的方案 - 在同一路径的。
从叶子节点开始。
假设以i为节点子树的数量分别为 sum1, sum2, sumk;(i必选)
那么对每子树选一个点。 其他子树选一个点。有 sumi * (n - 1 - sumi)
然后对i的子树选一个点,i树以外选一个点。
结果会重复算了一次。 所以要除上2
dfs时用的是 树形DP!
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#pragma comment(linker, "/STACK:16777216")
using namespace std;
__int64 ans;
int n;
bool vis[100005];
vector<int>vec[100005];
int dfs(int index) {
int sum = 0; //所有子树点的个数
vis[index] = true;
for(int i = 0; i < vec[index].size(); ++i)
if(!vis[vec[index][i]]) {
int temp = dfs(vec[index][i]); // 某棵子树的个数
sum += temp;
ans += (__int64) temp * (n - 1 - temp);
// printf("%d %d: %d %d %I64d\n",index,vec[index][i], temp, sum, ans);
}
if(sum)
ans += (__int64) sum * (n - 1 - sum);
sum++;
return sum;
}
int main()
{
int a,b,i,j;
while(~scanf("%d",&n))
{
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
vec[a].push_back(b);
vec[b].push_back(a);
}
ans=0;
memset(vis,0,sizeof(vis));
dfs(1);
__int64 tot=(__int64) n*(n-1)*(n-2)/6; //此处要用强制转换,不然会越界!! 3WR
printf("%I64d\n",tot-ans/2);
for(i=1;i<=n;i++)
vec[i].clear();
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:16777216")
#define V 100050
using namespace std;
struct Node
{
int pre,v;
}e[V*2];
int p[V*2],num;
bool vis[V*2];
__int64 ans,n;
void addedge(int u,int v)
{
e[num].v=v;
e[num].pre=p[u];
p[u]=num++;
}
int dfs(int index)
{
int i,j,sum=0;
vis[index]=1;
for(j=p[index]; j!=-1; j=e[j].pre)
{
int v=e[j].v;
if(vis[v]) continue;
int tmp=dfs(v);
sum+=tmp;
ans+= (__int64)tmp*(n-1-tmp);
}
if(sum) ans+=sum*(n-1-sum);
sum++;
return sum;
}
int main()
{
int i,j,a,b;
while(~scanf("%I64d",&n))
{
memset(p,-1,sizeof(p));
memset(vis,0,sizeof(vis));
num=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
/* for(i=1;i<=n;i++)
{
printf("%d: ",i);
for(j=p[i];j!=-1;j=e[j].pre)
printf("%d ",e[j].v);
printf("\n");
} */
ans=0;
dfs(1);
__int64 tot= n*(n-1)*(n-2)/6;
printf("%I64d\n",tot-ans/2);
}
return 0;
}