hdu 2874 Connections between cities LCA || dfs+並查集

題意: 

給出一些樹:有n(10000), m條邊(10000), c(1000000)個詢問,每個詢問a b要求找到a到b的最短距離,如果ab不在同一棵樹,輸出-1.

題解:

此題就是找兩個節點的最近公共祖先,則兩者的距離就是a和b到根節點的距離之和 - 2倍公共祖先到根節點的距離。可用離線的LCA算法,其實就是dfs+並查集,下面分析一下離線的LCA, 我是看了原理後,自己敲出的代碼。

LCA:

離線的LCA,其實就是說,只用一次dfs遍歷所有的節點,就可以找出任意兩個節點的距離,但是問題是,由於節點太多,無法保存任意兩個節點的距離,所以在具體應用中,需要先保存詢問,然後在dfs的過程中,只需要保存詢問的節點的答案即可。LCA: 其實就是先序遍歷這棵樹,然後當訪問完一個節點後,就把這個節點和他的父節點用並查集併到一起,那麼當訪問到要詢問的節點U後,只需要判斷詢問邊的另一個節點V是否被訪問過了,如果被訪問過了,則V的父節點就是兩者的最近公共祖先。

細節:

在本題中,可能不止一顆樹,所以在處理過程中,可以增加一個虛擬的0節點,作爲所有節點的根節點,這樣,如果訪問節點的父節點是0節點,就代表這兩個節點不屬於同一棵樹,則他們應該輸出-1.

代碼:

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1e4 + 10;
int n, m, c, fa[maxn], ans[1000000+10], vis[maxn], dist[maxn];
struct Node{
    int v, d;
    Node(int v = 0, int d = 0) : v(v), d(d){}
};
vector<Node> G[maxn];
vector<Node> query[maxn];

int findSet(int x)
{
    if (x != fa[x]) {
        fa[x] = findSet(fa[x]);
    }
    return fa[x];
}
void init()
{
    for (int i = 0; i <= n; i++)
    {
        fa[i] = i;
        dist[i] = 0;
        vis[i] = 0;
        G[i].clear();
        query[i].clear();
    }
    for (int i = 0; i < m; i++)
    {
        int u, v, d; scanf("%d%d%d", &u, &v, &d);
        G[u].push_back(Node(v, d));
        G[v].push_back(Node(u, d));
        int fu = findSet(u), fv = findSet(v);
        if (fu != fv) {
            fa[fu] = fv;
        }
    }
    for (int i = 1; i <= n; i++) {
        int fi = findSet(i);
        if (fa[fi] == i) {
            G[0].push_back(Node(i, 0));
        }
    }
    for (int i = 0; i <= n; i++) {
        fa[i] = i;
    }
    for (int i = 0; i < c; i++) {
        int u, v; scanf("%d%d", &u, &v);
        ans[i] = -1;
        query[u].push_back(Node(v, i));
        query[v].push_back(Node(u, i));
    }
}
void print()
{
    for (int i = 0; i < c; i++) {
        if (ans[i] != -1) {
            printf("%d\n", ans[i]);
        }
        else printf("Not connected\n");
    }
}
void dfs(int u)
{
    vis[u] = 1;
    for (int i = 0; i < query[u].size(); i++)
    {
        int fv = findSet(query[u][i].v);
        if (vis[query[u][i].v] && fa[fv] != 0)
        {
            ans[query[u][i].d] = dist[query[u][i].v] + dist[u] - 2*dist[fa[fv]];
        }
    }
    for (int i = 0; i < G[u].size(); i++)
    {
        if (vis[G[u][i].v]) continue;
        
        dist[G[u][i].v] = dist[u] + G[u][i].d;
        dfs(G[u][i].v);
        int fv = findSet(G[u][i].v);
        int fu = findSet(u);
        fa[fv] = fa[fu];
    }
}
int main()
{
//    freopen("/Users/apple/Desktop/in.txt", "r", stdin);
    while (scanf("%d%d%d", &n, &m, &c) != EOF)
    {
        init();
        dfs(0);
        print();
    }
    
    return 0;
}

發佈了30 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章