【Dijkstra】个人练习-Leetcode-882. Reachable Nodes In Subdivided Graph

题目链接:https://leetcode.cn/problems/reachable-nodes-in-subdivided-graph/

题目大意:给出一个图,给出所有边及其细分情况edges[],在每个边中插入cnt_i个细分点。给出移动最大步数maxMoves,求从0节点开始,在最大步数内,能够访问到的节点(包括原来的节点和细分节点)的数量。

思路:DFS做,到达一个原节点就减去一定步数,并将剩余步数传递,做下一步的DFS。如果步数不够,那么就记录从这个点到邻居点能够走的步数(也就是细分节点的数量)。最后将访问到的原节点和细分节点数相加。但开始时没考虑先算出到每个原节点的最短距离,而是单纯靠着步数去做,还有些测试点过不了。

单纯DFS代码

class Solution {
public:
    vector<vector<int>> dis;
    vector<vector<int>> mv;
    vector<vector<int>> adj;
    vector<bool> known;

    void DFS(int last, int node, int move) {
        // if (known[node])
        //     return;

        known[node] = true;
        if (move == 0)
            return;
        
        for (auto neb : adj[node]) {
            if (neb != last) {
                if (mv[node][neb] + mv[neb][node] < dis[node][neb]-1 || dis[node][neb] == 1) {
                    if (move >= dis[node][neb]) {
                        mv[node][neb] = dis[node][neb]-1;
                        DFS(node, neb, move - dis[node][neb]);
                    }
                    else
                        mv[node][neb] = max(mv[node][neb], move);
                }
            }
        }

        return;
    }

    int reachableNodes(vector<vector<int>>& edges, int maxMoves, int n) {
        const int MAXD = 0x7FFFFFFF;
        dis.resize(n, vector<int>(n, MAXD));
        mv.resize(n, vector<int>(n, 0));
        adj.resize(n, vector<int>(0));
        known.resize(n, false);

        for (auto e : edges) {
            int u = e[0], v = e[1], cnt = e[2];
            dis[u][v] = dis[v][u] = cnt+1;
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
        
        DFS(-1, 0, maxMoves);
        int ret = 0;
        for (int i = 0; i < n; i++)
            ret += known[i];
        for (auto e : edges) {
            int u = e[0], v = e[1], cnt = e[2];
            if (mv[u][v] + mv[v][u] < dis[u][v])
                ret += mv[u][v] + mv[v][u];
            else
                ret += dis[u][v]-1;
        }

        return ret;
    }
};

题解基本上都是Dijkstra做,先得出从0到所有原节点所需的最少步数,随后将能访问到的原节点和细分节点数加起来。

完整代码

class Solution {
public:
    vector<int> dist;
    vector<vector<pair<int, int>>> G;

    void Dij(int start) {
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
        pq.emplace(0, start);
        while (!pq.empty()) {
            auto [d, x] = pq.top();
            pq.pop();
            if (d > dist[x])
                continue;
            for (auto [neb, neb_d] : G[x]) {
                int tmp_d = dist[x] + neb_d;
                if (tmp_d < dist[neb]) {
                    dist[neb] = tmp_d;
                    pq.emplace(tmp_d, neb);
                }
            }
        }
    }

    int reachableNodes(vector<vector<int>>& edges, int maxMoves, int n) {
        const int MAXD = 0x7FFFFFFF;
        G.resize(n);
        dist.resize(n, MAXD);

        for (auto e : edges) {
            int u = e[0], v = e[1], cnt = e[2];
            G[u].emplace_back(v, cnt+1);
            G[v].emplace_back(u, cnt+1);
        }

        dist[0] = 0;

        Dij(0);

        int ret = 0;
        for (auto d : dist) {
            if (d <= maxMoves)
                ret++;
        }

        for (auto e : edges) {
            int u = e[0], v = e[1], cnt = e[2];
            int u2v = max(maxMoves - dist[u], 0);
            int v2u = max(maxMoves - dist[v], 0);
            ret += min(v2u + u2v, cnt);
        }

        return ret;
    }
        
};

你可能感兴趣的:(leetcode,深度优先,算法)