Connections between cities HDU

题意:

    给出n个点m条边的图,c次询问 求询问中两个点间的最短距离。

解析:

  Floyd会T,所以用到了最短路树。。具体思想为:

  设k为u和v的最近公共祖先 d[i] 为祖结点到i的最短距离  则dis[u][v] = d[u] + d[v] - 2*d[k]

  用tarjan的lca求即可

  把这题代码当作模板就好啦

  

#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#define rap(i, a, n) for(int i=a; i<=n; i++)
#define MOD 2018
#define LL long long
#define ULL unsigned long long
#define Pair pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define _  ios_base::sync_with_stdio(0),cin.tie(0)
//freopen("1.txt", "r", stdin);
using namespace std;
const int maxn = 10010, INF = 0x7fffffff;
const int maxm = 1e6 + 10;
int n, m, cnt1, cnt2, c;
int head1[maxn], head2[maxn], f[maxn], d[maxn], vis[maxn];
int res[maxm];


struct node
{
    int v, w, next;
}Node[maxn*2];

struct edge
{
    int v, id, next;
}Edge[maxm*2];

void add1_(int u, int v, int w)
{
    Node[cnt1].v = v;
    Node[cnt1].w = w;
    Node[cnt1].next = head1[u];
    head1[u] = cnt1++;
}

void add1(int u, int v, int w)
{
    add1_(u, v, w);
    add1_(v, u, w);
}

void add2_(int u, int v, int id)
{
    Edge[cnt2].v = v;
    Edge[cnt2].id = id;
    Edge[cnt2].next = head2[u];
    head2[u] = cnt2++;
}

void add2(int u, int v, int id)
{
    add2_(u, v, id);
    add2_(v, u, id);
}

int find(int x)
{
    return f[x]==x?x:(f[x] = find(f[x]));
}

int lca(int u, int deep, int root)
{
    f[u] = u;
    d[u] = deep; 
    vis[u] = root;  // 标记属于的树
    for(int i=head1[u]; i!=-1; i=Node[i].next)
    {
        node e = Node[i];
        if(vis[e.v] == -1)
        {
            lca(e.v, deep+e.w, root);
            f[e.v] = u;
        }
    }
    for(int i=head2[u]; i!=-1; i=Edge[i].next)
    {
        edge e = Edge[i];
        if(vis[e.v] == root)   //判断另一个结点是不是和u属于一个树
        {
            int k = find(e.v);  //寻找最近公共祖先
            res[e.id] = d[u] + d[e.v] - 2*d[k];
        }
    }
}

void init()
{
    mem(head1, -1);
    mem(head2, -1);
    mem(res, -1);
    mem(vis, -1);
    cnt1 = cnt2 = 0;
}


int main()
{
    while(scanf("%d%d%d", &n, &m, &c) != EOF)
    {
        init();
        rap(i, 1, m)
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add1(u, v, w);
        }
        rap(i, 1, c)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add2(u, v, i);
        }
        rap(i, 1, n)
            if(vis[i] == -1)
                lca(i, 0, i);
        rap(i, 1, c)
        {
            if(res[i] == -1) printf("Not connected
");
            else printf("%d
", res[i]);
        }
    }

    return 0;
}
自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
原文地址:https://www.cnblogs.com/WTSRUVF/p/9404495.html