给定一颗无根树,问有多少棵它的子树具有和他相同的重心?如果一棵树有两个根,那么子树也同样要有那两个重心。
首先找到树的重心,重心上连的每个节点所带领的子树的节点个数的两倍都不会超过n,如果是两个重心的话,两边的总节点个数应该是相同的
用树形dp求出每个节点所带领的子树的节点个数为i的时候的方案数,最后枚举总共的节点数,用dp求出总结点数为n的时候的方案数,相加得到结果
数据略水...貌似数据是随机生成的..所以没有出现有两个重心的树...
时限挺紧的..200^3的复杂度竟然T了..加了常数优化以后才A...
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=10007;
struct Node {
int dp[200];
int fe,num;
bool visited;
};
struct Edge {
int t,ne;
};
int n,center1,center2,p,maxsize;
Node a[201];
Edge b[400];
void putedge(int x,int y) {
b[p].t=y;
b[p].ne=a[x].fe;
a[x].fe=p++;
}
void getnum(int i) {
a[i].visited=true;
int maxn=0;
a[i].num=1;
for (int j=a[i].fe;j!=-1;j=b[j].ne) {
if (!a[b[j].t].visited) {
getnum(b[j].t);
a[i].num+=a[b[j].t].num;
if (maxn<a[b[j].t].num) maxn=a[b[j].t].num;
}
}
if (maxn<n-a[i].num) maxn=n-a[i].num;
if (maxsize>maxn) {
maxsize=maxn;
center1=i;
center2=-1;
maxsize=maxn;
} else if (maxsize==maxn) {
center2=i;
}
a[i].visited=false;
}
int tmpdp[200];
void getdp(int i) {
a[i].visited=true;
a[i].num=1;
a[i].dp[1]=1;
for (int j=a[i].fe;j!=-1;j=b[j].ne) {
if (!a[b[j].t].visited) {
getdp(b[j].t);
if (i!=center1&&i!=center2) {
memcpy(tmpdp,a[i].dp,sizeof(tmpdp));
memset(a[i].dp,0,sizeof(tmpdp));
for (int p=0;p<=a[i].num;p++) {
for (int q=0;q<=a[b[j].t].num;q++) {
a[i].dp[p+q]=(a[i].dp[p+q]+tmpdp[p]*a[b[j].t].dp[q])%mod;
}
}
}
a[i].num+=a[b[j].t].num;
}
}
a[i].dp[0]=1;
a[i].visited=false;
}
int getans(int center,int nn,int n) {
//printf("%d %d %d\n",center,nn,n);
memset(a[center].dp,0,sizeof(a[center].dp));
a[center].dp[0]=1;
for (int j=a[center].fe;j!=-1;j=b[j].ne) {
if (!a[b[j].t].visited) {
memcpy(tmpdp,a[center].dp,sizeof(tmpdp));
memset(a[center].dp,0,sizeof(tmpdp));
int num=a[b[j].t].num;
for (int p=0;p<=nn;p++) {
int *centerpq=&a[center].dp[p];
int tmp=tmpdp[p];
int *dpq=&a[b[j].t].dp[0];
for (int q=0;p+q<=nn&&q+q<n&&q<=num;q++,centerpq++,dpq++) {
*centerpq=(*centerpq+tmp*(*dpq))%mod;
}
}
}
}
//printf("%d\n",a[center].dp[nn]);
return a[center].dp[nn];
}
void print() {
for (int i=1;i<=n;i++) {
for (int j=0;j<n;j++)
printf("%d ",a[i].dp[j]);
printf("\n");
}
}
int main() {
int t,tt,x,y,i;
int ans;
scanf("%d",&t);
for (tt=1;tt<=t;tt++) {
scanf("%d",&n);
for (i=1;i<=n;i++) {
memset(a[i].dp,0,sizeof(a[i].dp));
a[i].fe=-1;
a[i].visited=false;
a[i].num=0;
}
p=0;
for (i=1;i<n;i++) {
scanf("%d%d",&x,&y);
putedge(x,y);
putedge(y,x);
}
maxsize=n;
center1=center2=-1;
getnum(1);
ans=0;
//printf("%d %d\n",center1,center2);
if (center2!=-1) {
a[center2].visited=true;
getdp(center1);
a[center1].visited=true;
getdp(center2);
a[center1].visited=a[center2].visited=true;
for (i=0;i+i+2<=n;i++) {
ans=(ans+getans(center1,i,i+i+2)*getans(center2,i,i+i+2))%mod;
}
} else {
getdp(center1);
for (i=0;i<n;i++) ans=(ans+getans(center1,i,i+1))%mod;
}
//print();
printf("Case %d: %d\n",tt,ans);
}
return 0;
}