树的重心
树的重心
分析:
就是在深搜的时候记录这个点的两边子节点的最大值
如果小于等于这个树上的点的数量的一半,就是重心。
代码长这样:
void dfs1(int x,int fa){
sizes[x]=wei[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
dfs1(y,x);
sizes[x]+=sizes[y];
if(wei[x]<sizes[y]) wei[x]=sizes[y];
}
wei[x]=max(wei[x],n-sizes[x]);
if(wei[x]<=n/2) zhongxin=x;
}
例题:
CF1406C Link Cut Centroids
题意:
给定一棵节点数为 \(n\) 的树 , 删一条边然后加上一条边 , 使得该树的重心唯一 。(删掉的边和加上的边可以是同一条)
分析:
如果只有一个重心,咋删都行
如果有两个重心,我们思考一下怎么才能变成一个重心
假如重心为 \(a1\) ,\(a2\) ,两者不算对方子树时,子树大小是相等的。
当子树大小不相等时,就只有一个重心。
因此可以断掉重心和连接点的一条边,将这条边连接到另一棵字数上,子树大小肯定不相等。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n;
int sizes[N],wei[N],q[4];
int nxt[N],ver[N],tot,head[N];
int cnt,ans1,ans2,minn;
void init(){
for(int i=0;i<=n;i++) sizes[i]=head[i]=wei[i]=0;
cnt=ans1=ans2=tot=0;
minn=0x3f3f3f3f;
}
void add(int x,int y){
ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot;
}
void dfs1(int x,int fa){
sizes[x]=wei[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
dfs1(y,x);
sizes[x]+=sizes[y];
if(wei[x]<sizes[y]) wei[x]=sizes[y];
}
wei[x]=max(wei[x],n-sizes[x]);
if(wei[x]<minn) minn=wei[x];
}
int dfs2(int x,int fa){
for(int i=head[x];i;i=nxt[i]){
int y=ver[i]; if(y==fa) continue;
ans2=x; return dfs2(y,x);
}
return x;
}
int main(){
cin>>T;
while(T--){
scanf("%d",&n); init();
for(int i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs1(1,0);
// for(int i=1;i<=n;i++) cout<<wei[i]<<" ";puts("");
for(int i=1;i<=n;i++) if(wei[i]==minn) q[++cnt]=i;
if(cnt==1) printf("%d %d\n%d %d\n",q[1],ver[head[q[1]]],q[1],ver[head[q[1]]]);
else{
int ans1=dfs2(q[2],q[1]);
printf("%d %d\n%d %d\n",ans2,ans1,q[1],ans1);
}
}
system("pause");
return 0;
}
P1364 医院设置
题意:
现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 \(1\)。
节点给定居民人数。
分析:
我们可以像树形 \(dp\) 一样转移状态:
首先,算出来每个节点作为 \(1\) 的子树,对应的子树人数大小。
我们可以据此算出来 节点 \(1\) 的答案大小
接着,过节点 \(1\) 的答案进行转移:
设从 \(x->y\) ,则左侧增加 \(sum-sizes[y]\) 的答案(就是以 \(x\) 为根,向 \(y\) 相反方向的子树大小),右侧减少 \(sizes[y]\) 的答案,加上 \(ans[x]\) 就是 \(ans[y]\)
最后输出最小值即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+5;
int nxt[N],ver[N],tot,head[N];
int val[N],sizes[N],peo[N];
int n,sum,root,ans=0x3f3f3f3f;
void add(int x,int y){
ver[++tot]=y;nxt[tot]=head[x]; head[x]=tot;
}
void dfs1(int x,int fa,int dep){
sizes[x]=val[x];
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
dfs1(y,x,dep+1);
sizes[x]+=sizes[y];
peo[x]=max(peo[x],sizes[y]);
}
peo[1]+=val[x]*dep;
}
void dfs2(int x,int fa){
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
peo[y]=peo[x]+sizes[1]-sizes[y]*2;
// = peo[x] +sizes[x]-sizes[y] 因为 sizes[x]=sum-sizes[y],所以就这样了
dfs2(y,x);
}
ans=min(ans,peo[x]);
}
signed main(){
cin>>n;
for(int i=1,z,x,y;i<=n;i++){
scanf("%lld%lld%lld",&val[i],&x,&y);
if(x) add(x,i),add(i,x);
if(y) add(y,i),add(i,y);
}
dfs1(1,0,0);
dfs2(1,0);
cout<<ans<<endl;
system("pause");
return 0;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9