概述
emmmm我之前那篇博客都是一些普及提高的树形DP水题,基本都是一个模板能够解决的问题。现在让我们来进阶一下。
**
T1
**
HOT-Hotels
传送门
有一个树形结构,每条边的长度相同,任意两个节点可以相互到达。选3个点。两两距离相等。有多少种方案?
难度:省选+/NOI-
这道题的难度并不是不能接受,一开始会觉得很难但是仔细想过之后会发现其实还好。
首先,我们要求任意三个点互相到达的距离相等,同时它是一个树形结构
所以,仔细想一下可以得知,如果要让三个点互相距离相同,那么只会有一种方案,也就是,一个中心店,即他们到这个中心点距离相同,然后它们之间互相的距离也是一样的。
如果一时不能理解的话,请想过后再往下看。
那么,这个这个中心点就成为了我们做这道题的入手。
我们可以枚举这个树形结构的每一个点作为根,那么,在我们每次枚举出的这棵树里,每一层的节点是不是就是高度相同?
也就是,这些点每三个就可以作为一个方案,
然后我们的任务就是来求方案了
根据小学乘法原理,
譬如这个根有三个子树,在这一层 的节点数分别是a,b,c,那么方案数是不是就是a*b*c?
同理如果这个根再多一个子树那么方案数是不是还要多
a∗b∗d+a∗c∗d+b∗c∗d
a
∗
b
∗
d
+
a
∗
c
∗
d
+
b
∗
c
∗
d
即
(a∗b+a∗c+b∗c)∗d
(
a
∗
b
+
a
∗
c
+
b
∗
c
)
∗
d
那么再多一颗子树也依然如此。
所以这就是我们的突破口了,
用一个sum2数组维护a*b+b*c+a*c………等这一式子;每次新得到的节点数为K
那么新增加的答案数为sum2*K;
设sum1为当前这一层当前子树之前的所有节点之和,
设tot[i]为当前子树第i层的节点数
那么框架就是
1.枚举根节点k
2.枚举每一棵子树,计算第i层的tot[i];
3.计算部分:
ans=ans+tot[i]∗sum2[i];
a
n
s
=
a
n
s
+
t
o
t
[
i
]
∗
s
u
m
2
[
i
]
;
sum2[i]=sum2[i]+sum1[i]∗tot[i]
s
u
m
2
[
i
]
=
s
u
m
2
[
i
]
+
s
u
m
1
[
i
]
∗
t
o
t
[
i
]
sum1[i]=sum1[i]+tot[i]
s
u
m
1
[
i
]
=
s
u
m
1
[
i
]
+
t
o
t
[
i
]
tot[i]=0//清零∗∗
t
o
t
[
i
]
=
0
/
/
清
零
∗
∗
然后就是每次枚举树根之后,sum1sum2要清零。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
int n,m,cnt,head[maxn],sum1[maxn],sum2[maxn],dep,tot[maxn];
long long ans;
inline int read()
{
int X=0,w=0; char c=0;
while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
return w?-X:X;
}
struct node
{
int v,nxt;
}e[maxn<<1];
void add(int u,int v)
{
cnt++;
e[cnt].nxt=head[u];
e[cnt].v=v;
head[u]=cnt;
}
void getfun(int v,int u,int deep)
{
dep=max(dep,deep);
tot[deep]++;
for (int i=head[v]; i; i=e[i].nxt)
{
int y=e[i].v;
if (y==u) continue;
getfun(y,v,deep+1);
}
}
int main()
{
n=read();
for (int i=1; i<n; i++)
{
int x,y;
x=read(),y=read();
add(x,y);
add(y,x);
}
for (int i=1; i<=n; i++)
{
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
for (int j=head[i]; j; j=e[j].nxt)
{
int v=e[j].v;
dep=0;
getfun(v,i,1);
for(int k=1;k<=dep;k++)
{
ans+=tot[k]*sum2[k];
sum2[k]=sum2[k]+sum1[k]*tot[k];
sum1[k]=sum1[k]+tot[k];
tot[k]=0;
}
}
}
cout<<ans;
}
大佬解法好
感谢大佬
最后
以上就是顺利凉面为你收集整理的树形DP 进阶题的全部内容,希望文章能够帮你解决树形DP 进阶题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复