树形枚举--搜索

题目描述:

给你一棵树,要在一条简单路径上选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. android自定义控件实例(Linearlayout组合TextView和ImageView)

    2013-12-18 11:25:22 转载自: http://www.open-open.com/lib/view/open1328836804515.html 很多时候android常用的控件不能 ...

  2. Android listview 制作表格样式+由下往上动画弹出效果实现

    效果是这样的:点击按下弹出表格的按钮,会由下往上弹出右边的列表,按下返回按钮就由上往下退出界面. 布局文件: activity_main.xml <RelativeLayout xmlns:an ...

  3. C++,1....n中随机等概率的输出m个不重复的数(假设n远大于m)。

    #include <stdlib.h> #include <time.h> knuth(int n, int m) { srand((unsigned )); ; i < ...

  4. [网络技术][转]PPTP协议解析

    PPTP协议大体上可以分为两部分:控制层连接和隧道,下面简要介绍两部分的功能.如果要详细了解PPTP协议请阅读RFC文档. 一. Control Connection Protol 控制层连接是基于T ...

  5. STM32之GPIO端口位带操作

    #ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //位带操作 //把“位带地址+位序号”转换别名地址宏 #define ...

  6. JVM-类文件结构

    无关性的基石 I> "平台无关性"实现在操作系统的应用层上:sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关 ...

  7. (转)UIApplication sharedApplication详细解释-IOS

    iPhone应用程序是由主函数main启动,它负责调用UIApplicationMain函数,该函数的形式如下所示: int UIApplicationMain ( int argc, char *a ...

  8. Javascript计数器

    <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content=&q ...

  9. hdu3473 线段树 划分树

    //Accepted 28904 KB 781 ms //划分树 //所求x即为l,r区间排序后的中位数t //然后求出小于t的数的和sum1,这个可以用划分树做 //求出整个区间的和sum,可以用O ...

  10. [UIImage resizableImageWithCapInsets:]使用注意

    转自:http://www.cnblogs.com/scorpiozj/p/3302270.html 最近在sae上搭建了个wp,因为深感自己前端的东西缺乏,所以想依次为契机,学习一下.本文是从个人的 ...