版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/82988775
题目链接:点击这里
解题思路:
因为边最多是点的+100,所以我们先生成一个生成树,然后剩下最多100个边.如果最小解不在生成树上面,那么最小解肯定会经过剩余100个边的某个端点,那么接下来把这剩下100个边的每个边拿去一个端点跑bfs(长度为1直接bfs)最短路,最后把生成树上面的最短路,和100个端点的最短路取最小就行了.
#include<bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 5;
int n,m,head[mx],tot,dep[mx];
int q[mx],tail,fa[mx][20];
int dis[105][mx],que[mx];
bool vis[mx];
struct node
{
int y,nxt;
}edge[2*mx+200];
void AddEdge(int x,int y)
{
edge[tot] = {y,head[x]};
head[x] = tot++;
edge[tot] = {x,head[y]};
head[y] = tot++;
}
void dfs(int x,int f)
{
vis[x] = 1;
dep[x] = dep[f] + 1;
fa[x][0] = f;
for(int i=head[x];~i;i=edge[i].nxt)
{
int u = edge[i].y;
if(u==f||vis[u]) continue;
dfs(u,x);
}
}
void RMQ(int N){//RMQfa[i]的2^j祖先
for(int j=1;(1<<j)<=N;j++)
for(int i=1;i<=N;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int i,j;
i=log(dep[u])/log(2.0);
for(j=i;j>=0;j--)
if((dep[u]-(1<<j))>=dep[v])
u=fa[u][j];//使u和v相同深度
if(u==v) return u;
for(j=i;j>=0;j--){
if(fa[u][j]!=fa[v][j]){//不断逼近
u=fa[u][j];
v=fa[v][j];
}
}
return fa[u][0];
}
void bfs(int* d,int x)
{
int h = 0,t = 1,tmp;
que[0] = x;
while(h!=t){
tmp = que[h++];
for(int i=head[tmp];~i;i=edge[i].nxt)
{
int u = edge[i].y;
if(d[u]||u==x) continue;
d[u] = d[tmp] + 1;
que[t++] = u;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
int a,b;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
AddEdge(a,b);
}
dfs(1,0),RMQ(n);
for(int i=0;i<tot;i+=2)
{
a = edge[i].y;
b = edge[i+1].y;
if(dep[a]+1!=dep[b]&&dep[b]+1!=dep[a])
q[tail++] = a;
}
sort(q,q+tail);
tail = unique(q,q+tail) - q;
for(int i=0;i<tail;i++) bfs(dis[i],q[i]);
scanf("%d",&m);
while(m--){
scanf("%d%d",&a,&b);
int ans = dep[a] + dep[b] - 2*dep[LCA(a,b)];
for(int i=0;i<tail;i++)
ans = min(ans,dis[i][a]+dis[i][b]);
printf("%d\n",ans);
}
return 0;
}