題意
有一個樹形結構,每條邊的長度相同,任意兩個節點可以相互到達。選3個點。兩兩距離相等。有多少種方案?
解析
滿足條件的點對一定是“有一箇中心點,三個點到中心點的距離相等,且三個點分別在不同子樹中”這種情況。(因爲如果在同一子樹中會被重複統計)。
那麼枚舉中心點,然後遍歷子樹,統計答案。
令cnt[i]表示當前子樹中深度爲i的點有多少個。
f[i]表示當前點已經遍歷過的子樹中,深度爲i的點有多少個。
g[i]表示當前點已經遍歷過的子樹中,兩個點深度都爲i的點對有多少個。
根據乘法原理ans += ∑(g[i] * cnt[i])。每次用f和cnt去更新g,用cnt去更新f。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)
using std :: max;
using std :: min;
typedef long long LL;
const int maxx = 100000 + 25;
int n,m,x,y,z,num;
LL ans;
int f[maxx],g[maxx],cnt[maxx],son[maxx];
int head[maxx],nxt[maxx],to[maxx];
void Ins(int x,int y){
to[++num] = y;nxt[num] = head[x];head[x] = num;son[x] ++;
}
void Dfs(int x,int pre,int dpt){
cnt[dpt] ++;
for(int i=head[x];i;i=nxt[i])
if(to[i] != pre)
Dfs(to[i],x,dpt+1);
}
int main(){
scanf("%d",&n);
For( i , 1 , n ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
Rep( x , 1 , n ){
if(son[x] < 3) continue;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=head[x];i;i=nxt[i]){
memset(cnt,0,sizeof(cnt));
Dfs(to[i],x,1);
Rep( k , 1 , n ){
ans += (LL)cnt[k] * g[k];
g[k] += f[k] * cnt[k];
f[k] += cnt[k];
}
}
}
printf("%lld\n",ans);
return 0;
}