FJOI2014 树的重心

\(Q\) 组测试数据。给一棵树大小为 \(n\),求有多少个子树与其重心相同。重心可能有多个。

数据范围:\(1\le Q\le 50\),\(1\le n\le 200\)。


就是要写好几个 \(\tt dp\) 吧,细节比较多。


先 \(\tt Dfs\) 一次找个重心:

int sz[N+7],g[N+7];
int Dfs1(int u,int fa){
int res=inf;
sz[u]=1,g[u]=0;
for(int&v:e[u])if(v!=fa){
res=min(res,Dfs1(v,u));
sz[u]+=sz[v],g[u]=max(g[u],sz[v]);
}
g[u]=max(g[u],n-sz[u]);
res=min(res,g[u]);
return res;
}
//...
int ms=Dfs1(1,0);
vector<int> G;
for(int i=1;i<=n;i++)if(g[i]==ms) G.pb(i);

重心只有 \(1\) 个或 \(2\) 个,于是分类讨论 。


  • 有 \(2\) 个重心

设重心为 \(Gx\) 和 \(Gy\)。

所以必然有边 \((Gx,Gy)\)。

把 \((Gx,Gy)\) 断开后两部分子树必然是相等的(要不然就只有 \(1\) 个重心)。

所以可以在两部分子树以 \(Gx,Gy\) 为根各写个 \(\tt dp\):

\(f_{u,i}\) 表示 \(u\) 点的子树选 \(i\) 个点的联通子树(包括 \(u\) 点)的方案数。

\[f_{u,i}=\sum_{v\in son_u}\sum_{j=1}^{\min(i-1,sz_v)}f_{u,i-j}\cdot f_{v,j}
\]

然后 \(Ans=\sum_{i=1}^{\min(sz_{Gx},sz_{Gy})}f_{Gx,i}\cdot f_{Gy,i}\)。

不过写两次树形 \(\tt dp\) 麻烦,我的代码中省了个树形 \(\tt dp\)。


  • 有 \(1\) 个重心

设重心为 \(G\)。

所以选出子树中 \(G\) 点的每个子树大小 \(\le\) 所有子树大小之和的 \(\frac 12\)。

所以可以先如上跑个 \(\tt dp\),以 \(G\) 为根得出同上的 \(f_{i,j}\)。

\(F_{i,j}\) 选出子树共 \(i\) 个点(除了 \(G\)),最大子树大小为 \(j\) 的方案数。

所以初始化 \(F_{i,i}=\sum_{v\in son_G}f_{v,i}\)。

\[{\rm Then}\forall k\in[1,i]:F_{i,\max(j,k)}+=F_{i-j,k}\cdot f_{v,j}
\]

最后 \(Ans=1+\sum_{i=1}^n\sum_{j=1}^n[2j\le i]F_{i,j}\)。

为什么要 \(+1\)?表示只选 \(G\) 点的情况。


  • 代码
#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=200,P=1e4+7;
int n;
vector<int> e[N+7]; //Treedp
int sz[N+7],g[N+7],f[N+7][N+7];
int Dfs1(int u,int fa){
int res=inf;
sz[u]=1,g[u]=0;
for(int&v:e[u])if(v!=fa){
res=min(res,Dfs1(v,u));
sz[u]+=sz[v],g[u]=max(g[u],sz[v]);
}
g[u]=max(g[u],n-sz[u]);
res=min(res,g[u]);
return res;
}
void Dfs2(int u,int fa){
sz[u]=f[u][0]=f[u][1]=1;
for(int&v:e[u])if(v!=fa){
Dfs2(v,u),sz[u]+=sz[v];
for(int i=sz[u];i>=1;i--)
for(int j=1;j<=min(sz[v],i-1);j++)
(f[u][i]+=f[u][i-j]*f[v][j]%P)%=P;
}
} //KonnyWen
int F1[N+7][N+7],F2[N+7];
int KonnyWen(){
scanf("%d",&n);
for(int i=1;i<=n;i++) e[i].clear();
for(int i=1,u,v;i<=n-1;i++){
scanf("%d%d",&u,&v);
e[u].pb(v),e[v].pb(u);
}
int ms=Dfs1(1,0);
vector<int> G;
for(int i=1;i<=n;i++)if(g[i]==ms) G.pb(i);
// puts("G:");
// for(int&x:G) printf("%d ",x);puts("");
memset(f,0,sizeof f),Dfs2(G[0],0);
// puts("f:");
// for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++)
// printf("%d%c",f[i][j],"\n "[j<n]);
int sm=0,res=0;
if(sz(G)==1){
memset(F1,0,sizeof F1),ms=-inf;
for(int&v:e[G[0]]){
ms=max(ms,sz[v]),sm+=sz[v];
for(int i=sm;i>=1;i--)
for(int j=min(sz[v],i);j>=1;j--){
if(j==i) (F1[i][j]+=f[v][j])%=P;
else for(int k=1;k<=min(i,ms);k++)
(F1[i][max(j,k)]+=F1[i-j][k]*f[v][j]%P)%=P;
}
}
// puts("F1:");
// for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++)
// printf("%d%c",F1[i][j],"\n "[j<n]);
for(int i=1;i<=sm;i++)
for(int j=1;j<=i;j++)
if(j*2<=i) (res+=F1[i][j])%=P;
res++;
} else if(sz(G)==2){ //一次树形 dp 代替两次
memset(F2,0,sizeof F2),F2[0]=1;
for(int&v:e[G[0]])if(v!=G[1]){
sm+=sz[v];
for(int i=sm;i>=1;i--)
for(int j=1;j<=min(sz[v],i);j++)
(F2[i]+=F2[i-j]*f[v][j]%P)%=P;
}
// puts("F2:");
// for(int i=1;i<=n;i++) printf("%d ",F2[i]);puts("");
for(int i=1;i<=sm+1;i++)
(res+=F2[i-1]*f[G[1]][i]%P)%=P;
}
return res;
} //Main
int main(){
int t; scanf("%d",&t);
for(int i=1;i<=t;i++)
printf("Case %d: %d\n",i,KonnyWen());
return 0;
}

祝大家学习愉快!

最新文章

  1. mono for android Listview 里面按钮 view Button click 注册方法 并且传值给其他Activity 主要是context
  2. (转)C# XMPP客户端与openfire通信(Matrix Xmpp 授权破解教程)
  3. 【知识积累】服务器端获取客户端的IP地址(当客户端调用由Axis开发的WebService)
  4. flume file channel 异常解决
  5. 『摄影欣赏』16幅 Romantic 风格照片欣赏【组图】
  6. QUnit使用笔记-1判断方法
  7. 20145235李涛《Java程序设计》第一周学习总结
  8. S2 第三章SQL编程
  9. poj 1258 Agri-Net 最小生成树 kruskal
  10. WinDbg x 64 使用 SOS: 无法找到运行时 DLL (clr.dll)
  11. Slf4j的包冲突
  12. No-Touch Integration 在SharePoint中使用社区支持的Silverlight应用程序
  13. LinkedHashMap:我还能实现LRU
  14. HDU1114Piggy-Bank(完全背包)
  15. Linux IPC实践(13) --System V IPC综合实践
  16. git-bash的alias别名设置
  17. 技术笔记1:java.sql.SQLException: Access denied for user &#39;root&#39;@&#39;localhost&#39; (using password)
  18. linux环境下安装jmeter,启动执行脚本
  19. Python实现百度贴吧自动顶贴机
  20. Android之androidmainfest.xml配置文件详解

热门文章

  1. one-wallhaven 一个壁纸程序
  2. JAVA学习准备
  3. Spring源码理论
  4. 背包问题(动态规划 C/C++)
  5. MFC的窗口句柄
  6. SixLabors.ImageSharp 实践小结
  7. webug第七关:越权
  8. 基于Pycharm的Python开发环境配置
  9. FL Studio中的文件设置介绍
  10. Idea中如何导入jar包