NKOJ3867 宾馆
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 1s
问题描述
何老板开了一间宾馆,共n个房间,通过n-1双向道路相连,每条道路的长度相同,任意两个房间都有且仅有一条路径可以到达。有三名同行的顾客需要各开一个房间。三个客人要求住的房间要互不相同,且三个房间两两距离相同。
何老板想知道,有多少种方案能让他们满意?
输入格式
第一行一个数n。
接下来n-1行,每行两个数x,y,表示x和y之间有一条道路相连。
输出格式
一个整数,表示满足要求的方案数。
样例输入 1
7
1 2
5 7
2 5
2 3
5 6
4 5
样例输出 1
5
样例输入 2
20
1 2
2 3
1 4
3 5
2 6
4 7
6 8
4 9
7 10
10 11
9 12
3 13
9 14
5 15
2 16
6 17
5 18
11 19
4 20
样例输出 2
18
提示
【样例1说明】
{1,3,5},{2,4,6},{2,4,7},{2,6,7},{4,6,7}
【数据范围】
对于30%的数据 1≤N≤100
对于100%的数据 1≤N≤5000
来源 改编自Poi2014 hotel
思路:三个房间两两间路径一定会经过一个中心点,所以依次枚举中心点。
对于某中心点z,再依次枚举各层子孙所能做出的贡献。
枚举子孙时,第一层,为儿子数选3个的组合。以后的每一层,暴力计算贡献数量。
注意:
剪枝1:枚举到某一层时,该子树已没有节点,以后都不枚举该子树了。
剪枝2:若该层有节点的子树小于3,也没有必要加深了
#include<cstdio>
#include<iostream>
#include<cmath>
#include<bitset>
#include<vector>
using namespace std;
const int need=5003;
int n;
vector<int> w[need];
typedef vector<int>::iterator iit;
//.................................................
inline void in_(int &d)
{
char t=getchar();
while(t<'0'||t>'9') t=getchar();
for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';
}
//.................................................
long long c(const int &n,int m=3)
{
if(m>n) return 0;
long long c[2]={1,};
for(int i=1;i<=m;i++) c[i&1]=c[(i+1)&1]*(n-i+1)/i;
return c[m&1];
}
int cnt_son(const int &fa,const int &k,int m)
{
if(m==1) return w[k].size()-1;
int son=0;
for(iit it=w[k].begin();it!=w[k].end();it++)
{
if(*it!=fa)son+=cnt_son(k,*it,m-1);
}
return son;
}
long long cnt(const int &k)
{
bitset<need> bt;
long long ans=c(w[k].size());
if(ans==0) return 0;
int son,tmp;
long long ctmp;
iit it,jt,kt;
for(int i=1;i<=5000;i++)
{
son=tmp=0,ctmp=1;
vector<int> ve;
for(it=w[k].begin();it!=w[k].end();it++)
{
if(bt[*it]) continue;
tmp=cnt_son(k,*it,i);
if(tmp)
{
if(ve.size()==2)
{
ctmp=ve[0]*ve[1]*tmp;
}
else if(ve.size()>2)
{
for(jt=ve.begin();jt<ve.end();jt++)
{
for(kt=jt+1;kt<ve.end();kt++)
{
if(kt==jt) continue;
ctmp+=tmp*(*jt)*(*kt);
}
}
}
ve.push_back(tmp);
}
else bt[*it]=1;
}
if(ve.size()>=3)ans+=ctmp;
else return ans;
}
}
//.................................................
int main()
{
scanf("%d",&n);
for(int i=1,a,b;i<n;i++)
{
in_(a),in_(b);
w[a].push_back(b);
w[b].push_back(a);
}
long long ans=0;
for(int i=1;i<=n;i++) ans+=cnt(i);
cout<<ans;
}