题目链接:uvalive 6436
题目大意:由n个结点,n-1条边构成的无向连通图。定义某个点的繁荣度为:由某个点到达另一个点所经过的次数。(比如:A--B--C,D--B--C。此时B的繁荣度为:2)
解题思路:某点的繁荣度可以确定为:子树1*子树2+子树1*子树3+...+子树1*子树n+子树2*子树1+子树2*子树3+...子树2*子树n+。。。最后除以 二就行了,因为重复了一次,比如子树1*子树2与子树2*子树1重复了。
直接上代码吧:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int maxn=20100;
vector<int> tre[maxn];//树的结构
int n,cnt[maxn];//某个结点的子树的个数
ll ans;
void dfs(int now,int pre)//当前结点,父亲结点
{
int len=tre[now].size();
int i,m;
ll sum=0;
cnt[now]=1;//初始化,因为每个结点必定与某个结点相连。
for(i=0;i<len;i++)
{
m=tre[now][i];
if(m==pre)
continue;
dfs(m,now);
cnt[now]+=cnt[m];
sum+=(ll)cnt[m]*(n-cnt[m]-1);//子树m与剩余子树的乘积,比如子树1*子树2+..子树1*子树n。
}
sum+=(ll)(cnt[now]-1)*(n-cnt[now]);//还得加上该点的父亲结点与该点的子树的乘积。
ans=max(sum,ans);
return ;
}
int main()
{
int t,i,s=0;
int a,b;
scanf("%d",&t);
while(t--)
{
memset(cnt,0,sizeof(cnt));
for(i=0;i<maxn;i++)
tre[i].clear();
ans=0;
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
tre[a].push_back(b);
tre[b].push_back(a);
}
dfs(1,0);
printf("Case #%d: %lld\n",++s,ans/2);
}
return 0;
}