树形枚举--搜索

题目描述:

给你一棵树,要在一条简单路径上选3个不同的点构成一个集合,问能构成多少个不同的集合。

解法:

枚举所有结点,假设某个结点有n棵子树,每棵子树的结点个数分别为s1,s2,````sn.那么在选中该结点后,剩下的两个结点从子树上选,考虑顺序,则有方案数ans =  s1*(sum(si) - s1) + s2*(sum(si) - s2) + ``` + sn*(sum(si) - sn),化简得ans = sum(si) ^ 2 - sum(si ^2) .实际上,另外两个点选了(1,2)和(2,1)对于集合{a,b,c}而言是一样的,所以方案数应该为ans/2。

而一个结点的子节点的总和为n-1。只要求sum(si^2)即可,由于是从某一点开始搜的,我们把这个点想成了根结点,实际上对于除这个点以外的其他点,除了按搜索顺序认为的子树外,剩下的结点是它的另一棵子树。

代码实现:

ll ans=0;

int dfs(int x)//返回该结点的某棵子树的结点个数

{

vis[x] =1;

ll sq=0;//”子树”结点个数的平方和

int tot =0;//”子树”结点个数的总和

for(int i=0; i<g[x].size(); ++i)

{

if(!vis[g[x][i]])

{

int son = dfs(g[x][i]);//子结点的个数

tot += son;

sq += (ll)son*son;

}

}

sq += (ll)(n-tot-1)*(n-tot-1);

ans += ((ll)(n-1)*(n-1) - sq)/2;

return tot+1;//当自己作为子树时,还要加上自己,所以加1.

}

另一种解法:

直接考虑顺序计数,有方案数ans =s1*(s2+s3+````+sn)+s2*(s3+s4+```sn) +```` + s[n-1]*sn. 则有设sum[i]为前i项和,则有ans = s1*(n-1-sum[1]) + s2*(n-1-sum[2]) +````+s[n-1]*(n-1-sum[n-1]) + sn *0.

代码实现:

ll ans;

int dfs(int x)

{

vis[x] =1;

int tmp=0;

for(int i=0; i<g[x].size(); ++i)

{

if(!vis[g[x][i]])

{

int son = dfs(g[x][i]);//当前分支的儿子个数

tmp += son;//已经求出的儿子个数,相当于sum[i]

ans += (ll)(n-1-tmp)*son;

}

}

return tmp+1;

}

然后此题的正解就是C(n,3)- ans.C(n,3)表示从n个点中选3个点,C(n,3) = n*(n-1)*(n-2)/6

贴代码1:

 #pragma comment(linker, "/STACK:16777216")
#include<cstdio>
#include<vector>
#define N 100010
using namespace std;
typedef long long int ll;
vector<int> g[N];
bool vis[N];
int n;
ll ans;
int dfs(int x)
{
vis[x] =;
ll sq=;//子节点个数的平方和
int tot =;//子节点个数之和
for(int i=; i<g[x].size(); ++i)
{
if(!vis[g[x][i]])
{
int son = dfs(g[x][i]);//子节点的个数
tot += son;
sq += (ll)son*son;
}
}
sq += (ll)(n-tot-)*(n-tot-);
ans += ((ll)(n-)*(n-) - sq)/;
return tot+;
}
int main()
{
freopen("1010.in","r",stdin);
while(~scanf("%d",&n))
{
for(int i=; i<=n; ++i)
{
g[i].clear();
vis[i] =;
}
for(int i=; i<n; ++i)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
ans =;
dfs();
ll sum = (ll)n*(n-)*(n-)/;
printf("%I64d\n",sum-ans);
}
return ;
}

贴代码2:

 #pragma comment(linker, "/STACK:16777216")
#include<cstdio>
#include<vector>
#define N 100010
using namespace std;
typedef long long int ll;
vector<int> g[N];
bool vis[N];
int n;
ll ans;
int dfs(int x)
{
vis[x] =;
int tmp=;
for(int i=; i<g[x].size(); ++i)
{
if(!vis[g[x][i]])
{
int son = dfs(g[x][i]);//当前分支的儿子个数
tmp += son;//已经求出的儿子个数
ans += (ll)(n--tmp)*son;
}
}
return tmp+;
}
int main()
{
// freopen("1010.in","r",stdin);
while(~scanf("%d",&n))
{
for(int i=; i<=n; ++i)
{
g[i].clear();
vis[i] =;
}
for(int i=; i<n; ++i)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
ans =;
dfs();
ll sum = (ll)n*(n-)*(n-)/;
printf("%I64d\n",sum-ans);
}
return ;
}

HDU 4705 Y 树形枚举的更多相关文章

  1. HDU 4705 Y (2013多校10,1010题,简单树形DP)

    Y Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submiss ...

  2. hdu 4705 Y (树形dp)

    Description Input 4 1 2 1 3 1 4 题目的意思是给你一棵树,让你找到所有不在一条路径上的三个点的情况个数.乍一看正向处理比较麻烦,我们从反方向考虑,如果是取在一条路径上的3 ...

  3. HDU 4705 Y

    Y Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submis ...

  4. HDOJ 4705 Y 树形DP

    DP:求出3点构成链的方案数 .然后总方案数减去它 Y Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K ...

  5. hdu 4705(树形DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4705 思路:反面考虑,用总的方案数减去A,B,C三点在同一路径上的方案数.于是我们可以确定中间点B,在 ...

  6. HDU 5778 abs (枚举)

    abs 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5778 Description Given a number x, ask positive ...

  7. HDU-4705 Y 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4705 题意:给一颗树,从树上任意选择3个点{A,B,C},要求他们不在一条链上,求总共的数目. 容易想 ...

  8. hdu 4756 MST+树形dp ****

    题意:给你n(n = 1000)个二维点,第一个点是power plant,还有n - 1个点是dormitories.然后现在知道有一条寝室到寝室的边是不能连的,但是我们不知道是哪条边,问这种情况下 ...

  9. hdu 4081 最小生成树+树形dp

    思路:直接先求一下最小生成树,然后用树形dp来求最优值.也就是两遍dfs. #include<iostream> #include<algorithm> #include< ...

随机推荐

  1. linux 安装vpn

    机器环境 centos Linux  wdcp安装脚本和步骤第一步: wget http://www.huzs.net/soft/pptp_onekey/pptpd6.sh sh pptpd6.sh ...

  2. mac下安装apache+php+mysql

    运行“sudo apachectl start”,再输入帐号密码,这样Apache就运行了. 运行“sudo apachectl -v”,你会看到Mac OS X 10.6.3中的Apache版本号: ...

  3. 在ubunut下使用pycharm和eclipse进行python远程调试

    我比较喜欢Pycharm,因为这个是JetBrains公司出的python IDE工具,该公司下的java IDE工具--IDEA,无论从界面还是操作上都甩eclipse几条街,但项目组里有些人使用e ...

  4. 嵌套遍历<s:iterator>map=new TreeMap(string,Map(string,User))

    //嵌套遍历,先给外层的map(假设是放在root中的,如果放在context的map中,要加#)取个别名,放到Actioncontext中 <s:iterator value="ma ...

  5. js对象的定义及处理

    一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascrip ...

  6. Ogre 1.8 terrain 和 paging 组件

    以下转自:http://hi.baidu.com/xocoder/item/e8d87cf53d87612b753c4cfd OGRE地形生成 OGRE可以通过两个接口来生成地形,分别是void Te ...

  7. ajax注释

    //xmlHttpRequest,但是这个对象只是在火狐,google...//在中国用的最广泛的IE浏览器里面是没有这个对象的//在IE里面是用的一个控件来解决这个问题,ActiveXObject/ ...

  8. UIWebView的缓存策略,清除cookie

    缓存策略 NSURLRequestCachePolicy NSURLRequestUseProtocolCachePolicy缓存策略定义在 web 协议实现中,用于请求特定的URL.是默认的URL缓 ...

  9. 如何将内存图像数据封装成QImage

    http://blog.csdn.net/lyc_daniel/article/details/9055787 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行处理(如缩放.旋转)操作. ...

  10. 如何在ubuntu 12.04 中安装经典的 GNOME桌面

    这次介绍的是如何在ubuntu 12.04 中安装经典的 GNOME桌面,默认的 Ubuntu 12.04 默认unity桌面,一些用户不喜欢 Unity 桌面,所以想找回昔日的经典Gnome桌面. ...