树形枚举--搜索

题目描述:

给你一棵树,要在一条简单路径上选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. Python中的sorted函数以及operator.itemgetter函数 【转载】

    operator.itemgetter函数operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子. a = [1,2 ...

  2. 数据结构-AVL树的旋转

    http://blog.csdn.net/GabrieL1026/article/details/6311339 平衡二叉树在进行插入操作的时候可能出现不平衡的情况,AVL树即是一种自平衡的二叉树,它 ...

  3. socket编程概述

    一.基本流程如下: 整个TCP过程非常类似于电话系统.TCP是有两个不同主机上的进程需要进行通信,电话系统是有两个人位于不同地区的人需要进行通信. socket:获得可用于进程通信的端点.由于Linu ...

  4. java基础之 集合

    一.ArrayList和Linkedlist的区别 1.ArrayList是基于数组,LinkedList基于链表实现. 对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开 ...

  5. SrcollView分页加载数据(布局)

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools=& ...

  6. [安卓]AndroidManifest.xml文件简介及结构

    1.AndroidManifest.xml文件简介: 每个应用程序在它的根目录中都必须要有一个AndroidManifest.xml(名字须精确一致)文件.这个清单把应用程序的基本信息提交给Andro ...

  7. Visual Studio环境色调配色

    据说对眼睛有好处的色调配色 vs 色调rgb 199,240,214 色调为84,饱和度为91,亮度为205 色调为85,饱和度为123,亮度205: “色调”由160更改为75-85之间——> ...

  8. NSURLSession的使用

    虽然在iOS7引入NSURLSession时,就知道NSURLConnection会最终被苹果放弃,但人总是喜欢做熟悉的事情,在NSURLConnection还可以使用时,就懒得学习这新玩意了,而且本 ...

  9. Integer 和int

    获取Integer对象有两种方式:Integer x = 100:或者Integer x = new Integer(100): Integer x = 100:等价于Integer x = Inte ...

  10. jenkins持续集成工具

    jenkins是开源的 持续集成.持续构建的可视化web工具,持续构建说直白,就是各种项目的自动化编译.打包.分发部署. 好很多优点: 1.支持多语言 2.跟svn.git能无缝集成 3.直接与知名源 ...