题意:给定一个图,然后找出所有到剩余点距离最近的点。(我这个看不懂也可以看看题目叭,我觉得题目讲的很易懂的)
题解:首先这题,既然我们要找出所有的点,那肯定是要求出所有点到剩余点的距离的。那这里我们用sum[i]表示i到其他点的距离和,只需要求出这个sum数组,那么我们遍历一遍就可以出来结果了。同时我们要对这个图有一个基本认知,如果你看到最后面的备注里面(图的类型保证没有大小大于等于3的环)应该就可以明白这是一个树了。
那么这个sum数组怎么求呢,总不可能每个点跑一次bfs/dijkstra吧。这里我们就要利用这个每个边都是1的特性了。我们采用dfs维护距离和的方法,假设当前节点是sum[x],我们要转移到sum[y],就有这么一条转移方程 sum[y]=sum[x]-cnt[y]+(n-cnt[y]).这个cnt[y]代表的是y这个节点的子树重量。从x到y这一步,y这个节点到y的子节点的距离全部都-1 故-cnt[y],同时不是子树的点,都+1,所以+(n-cnt[y])。那到了这一步,我们需要求出cnt数组了。我们假设刚开始以1为根,然后dfs回溯的时候算出cnt。最后再来一次dfs维护距离和,求出sum数组。问题就得到解决。
具体操作可以看看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,u,v;
const int N=5e4+5;
vector<int>g[N];
ll cnt[N],sum[N],dep[N];
ll mn;
map<int,map<int,int> >qaq;
void dfs1(int p,int fa){
dep[p]=dep[fa]+1;//求出每个点的深度也就是到根(1)的距离啦
cnt[p]=1;
for (int i=0;i<g[p].size();i++)
if (g[p][i]!=fa)
{dfs1(g[p][i],p);cnt[p]+=cnt[g[p][i]];}
}
void dfs2(int p,int fa){
for (int i=0;i<g[p].size();i++)
if (g[p][i]!=fa)
{sum[g[p][i]]=sum[p]-cnt[g[p][i]]+(n-cnt[g[p][i]]);
mn=min(mn,sum[g[p][i]]);
dfs2(g[p][i],p);}
}
int main() {
cin>>n>>m;
for (int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
if (qaq[u][v]==0&&qaq[v][u]==0){//记得判断重边
qaq[u][v]=1;
qaq[v][u]=1;
g[u].push_back(v);
g[v].push_back(u);
}
}
dep[0]=-1;
dfs1(1,0);
for (int i=1;i<=n;i++)
sum[1]+=dep[i];//求出一个sum用于转移
mn=sum[1];
dfs2(1,0);
int first=1;
for (int i=1;i<=n;i++){
if (sum[i]==mn){
if (first){
printf("%d",i);
first=0;
}
else
printf(" %d",i);
}
}
puts("");
return 0;
}



京公网安备 11010502036488号