题意: 给定无环无向 不一定连通的图,求任意点间最短距离
n个点 m条无向边 que个询问
下面u v dis 为边及边长
下面que行
u v表示u v点最近距离
思路:
LCA转RMQ ,用并查集判断点是否连通
#include <iostream> #include<cstdio> #include<string.h> #include<math.h> #define N 10010 using namespace std; inline int Max(int a,int b){return a>b?a:b;} inline int Min(int a,int b){return a<b?a:b;} struct Edge{ int from, to, dis, nex; }edge[N*2]; int head[N], edgenum; void addedge(int u, int v, int d){ Edge E = {u, v, d, head[u]}; edge[ edgenum ] = E; head[u] = edgenum++; } int f[N]; int find(int x){return x==f[x] ? x : (f[x] = find(f[x]));} void Union(int x, int y){ int fx = find(x), fy = find(y); if(fx<fy) f[ fx ] = fy; else f[ fy ] = fx; } int deep [N<<1]; //第i个访问的结点的深度 int index[N<<1]; //第i个访问的结点的编号 int first[N]; //第i个结点是第几个访问的 int DIS[N]; //到root的距离 int dp[N<<1][16]; //dp[i][j] 为从 i开始到 i+2^j-1 区间内的最值 , 我们可以讲这段2^j的区间分成两部分长度都为2^(j-1)的相同区间 int time; void DFS(int u, int dep){ index[time] = u; deep [time] = dep; time ++; for(int i = head[u]; i!=-1; i = edge[i].nex) { int v = edge[i].to; if(first[v] == 0) { first[v] = time; DIS[v] = DIS[u] + edge[i].dis; DFS(v, dep+1); index[time] = u; deep [time] = dep; time++; } } } //F[i][j] =Max( F[i][j-1],F[i+2^(j-1)][j-1] ),边界条件为F[i][0]=A[i]. //由于大的区间是由小的区间得到的,所以预处理时必须按区间长度递增的顺序递推出F[i][j]. void RMQ_init(int n){ int i, j; for(i = 1; i <= n; i++)//初始化dp数组 dp[i][0] = i; for(j = 1; 1<<j <= n; j++) { int k = 1<<(j-1); for(i = 1; i+k < n; i++) { if(deep[dp[i][j-1]] <= deep[dp[i+k][j-1]]) dp[i][j] = dp[i][j-1]; else dp[i][j] = dp[i+k][j-1]; } } } //查询:求区间[ i , j ]的最值 令 d=(int) log2( j-i+1) //我们取靠i的长度为2^d区间 以及靠j的2^d区间内的最大值 ,两个区间内可以存在公共部分 //则i,j max= Max ( F[i][d] ,F[j-2^d+1,d]) int RMQ(int a, int b){ int dis = abs(b-a) + 1; int k = log(double(dis)) / log(2.0); if(deep[dp[a][k]] <= deep[dp[b-(1<<k)+1][k]]) return dp[a][k]; else return dp[b-(1<<k)+1][k]; } int LCA(int u, int v){ int fu = first[u], fv = first[v]; return fu <= fv ? index[ RMQ(fu, fv) ] : index[ RMQ(fv, fu) ]; } bool Ispoint[N];//i点是否为根节点,是则与虚拟根节点0相连 void init(int n){ memset(head, -1, sizeof(head)); edgenum = 0; memset(Ispoint, 0, sizeof(Ispoint)); memset(first, 0, sizeof(first)); for(int i = 1; i <= n; i++)f[i] = i; } int main() { int i, j, n, que, m, u, v, d; int root = 0; while(~scanf("%d%d%d",&n,&m,&que)) { init(n); while(m--) { scanf("%d %d %d",&u, &v, &d); addedge(u, v, d); addedge(v, u, d); Union(u, v); } for(i = 1; i <= n; i++)find(i); for(i = 1; i <= n; i++)Ispoint[ f[i] ] = true; for(i = 1; i <= n; i++) if(Ispoint[i]) addedge(root, i, 0); time = 1; first[root] = time; DIS[root] = 0; DFS(root, 0); RMQ_init(time-1); while(que--){ scanf("%d %d",&u, &v); if(f[u] != f[v]){printf("Not connected\n");continue;} if(u == v){printf("0\n");continue;} printf("%d\n",DIS[u]+DIS[v] - 2*DIS[ LCA(u, v) ]); } } return 0; }