版权声明:选经典题目,写精品文章. https://blog.csdn.net/nka_kun/article/details/82827287
题意:给出一个图,询问任意两点之间最短路,边比点多不过20.
思路:因为边多的很少,所以可以看成一个树,又多加了几条边.这样其实我们可以把那几个点看成中转节点,这样我们可以求出那些点到任意点的最短路径,然后询问的时候,对于x,y,要不从树上直接从x,y这里用lca即可,要么经过其中一个节点,为什么不是结果其中几个节点呢?其实经过一个节点就够了,那个节点到任意节点的最短路我们是知道的,他如果需要会自动经过几个节点的.
代码:
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;
struct edge
{
int u,v,ne;
ll w;
}e[maxn];
struct node
{
int pos;
ll cost;
node(){}
node(int x,ll y):pos(x),cost(y){}
friend bool operator < (node x,node y)
{
return x.cost> y.cost;
}
};
int n,m;
int head[maxn],len;
ll v[maxn][3],d[maxn],dis[45][maxn];
int vis[maxn],pre[maxn];
bool book[maxn];
int deep[maxn],f[maxn],anc[maxn][20];
int find(int x)
{
return pre[x] == x?x:pre[x] = find(pre[x]);
}
void add(int u,int v,ll w)
{
e[len].u = u;
e[len].v = v;
e[len].w = w;
e[len].ne = head[u];
head[u] = len++;
}
void dfs(int x,int p,ll w)
{
deep[x] = deep[p]+1;
f[x] = p;
anc[x][0] = p;
d[x] = w;
for(int i = 1;i<= 19;i++)
anc[x][i] = anc[anc[x][i-1]][i-1];
for(int i = head[x];i!= -1;i = e[i].ne)
{
if(e[i].v == p) continue;
dfs(e[i].v,x,w+e[i].w);
}
return ;
}
int lca(int x,int y)
{
if(deep[x]< deep[y])
swap(x,y);
for(int i = 19;i>= 0;i--)
if(deep[x]-(1<<i)>= deep[y])
x = anc[x][i];
if(x == y) return x;
for(int i = 19;i>= 0;i--)
if(anc[x][i]!= anc[y][i])
x = anc[x][i],y = anc[y][i];
return anc[x][0];
}
void DJ(int sx,int t)
{
for(int i = 1;i<= n;i++) dis[t][i] = 1e15;
mem(book,0);
priority_queue<node> q;
q.push(node(sx,0));
dis[t][sx] = 0;
while(!q.empty())
{
node now = q.top();
q.pop();
if(book[now.pos]) continue;
book[now.pos] = 1;
for(int i = head[now.pos];i!= -1;i = e[i].ne)
{
int id = e[i].v;
if(dis[t][id]> dis[t][now.pos]+e[i].w)
{
dis[t][id] = dis[t][now.pos]+e[i].w;
q.push(node(id,dis[t][id]));
}
}
}
return ;
}
int main()
{
mem(head,-1);
cin>>n>>m;
for(int i = 1;i<= n;i++) pre[i] = i;
for(int i = 1;i<= m;i++)
scanf("%lld %lld %lld",&v[i][0],&v[i][1],&v[i][2]);
for(int i = 1;i<= m;i++)
{
int fx = find(v[i][0]);
int fy = find(v[i][1]);
if(fx!= fy)
{
vis[i] = 1;
pre[fy] = fx;
add((int)v[i][0],(int)v[i][1],v[i][2]);
add((int)v[i][1],(int)v[i][0],v[i][2]);
}
}
dfs(1,0,0);
for(int i = 1;i<= m;i++)
{
if(!vis[i])
{
add((int)v[i][0],(int)v[i][1],v[i][2]);
add((int)v[i][1],(int)v[i][0],v[i][2]);
}
}
int cnt = 0;
for(int i = 1;i<= m;i++)
{
if(!vis[i])
{
cnt++;
DJ((int)v[i][0],cnt);
cnt++;
DJ((int)v[i][1],cnt);
}
}
int q;
cin>>q;
while(q--)
{
int x,y;
scanf("%d %d",&x,&y);
int fa = lca(x,y);
ll ans = d[x]-d[fa]+d[y]-d[fa];
for(int i = 1;i<= cnt;i++)
ans = min(dis[i][x]+dis[i][y],ans);
printf("%lld\n",ans);
}
return 0;
}