问题描述
何老板开了一间宾馆,共n个房间,通过n-1双向道路相连,每条道路的长度相同,任意两个房间都有且仅有一条路径可以到达。有三名同行的顾客需要各开一个房间。三个客人要求住的房间要互不相同,且三个房间两两距离相同。
何老板想知道,有多少种方案能让他们满意?
输入格式
第一行一个数n。
接下来n-1行,每行两个数x,y,表示x和y之间有一条道路相连。
输出格式
一个整数,表示满足要求的方案数。
题解
已知若三点两两间距离相等,那么必定存在一点到三点之间距离相同。
考虑到数据范围,暴力枚举每个点,考虑每一个该点的子树的贡献。
代码中的计算方式非常机智
s1表示选一种可能的情况
s2表示选两种可能的情况
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define maxn 10005
#define ll long long
int Next[maxn],Last[maxn],End[maxn];
int num[maxn];
ll sum,s1[maxn],s2[maxn],ans;
int cnt;
int dep[maxn];
int n;
int maxx;
void insert(int x,int y)
{
Next[++cnt]=Last[x];
Last[x]=cnt;
End[cnt]=y;
}
void dfs(int x,int fr,int y)
{
maxx=max(maxx,y);
dep[y]++;
for(int i=Last[x];i;i=Next[i]){
int en=End[i];
if(en!=fr){
dfs(en,x,y+1);
}
}
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n-1;i++){
int x,y;
scanf("%d%d",&x,&y);
insert(x,y);
insert(y,x);
}
for(i=1;i<=n;i++){
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
maxx=0;
for(j=Last[i];j;j=Next[j]){
memset(dep,0,sizeof(dep));
int en=End[j];
dfs(en,i,1);
for(int k=1;k<=maxx;k++){
ans+=dep[k]*s2[k];
s2[k]+=s1[k]*dep[k];
s1[k]+=dep[k];
}
}
}
cout<<ans;
}