题意:给定一个图,然后找出所有到剩余点距离最近的点。(我这个看不懂也可以看看题目叭,我觉得题目讲的很易懂的)
题解:首先这题,既然我们要找出所有的点,那肯定是要求出所有点到剩余点的距离的。那这里我们用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;
}