• 题解 P2296 【寻找道路】


    主要思路:DFS + Dijkstra + 堆优化 + 反向思维

    要不是写代码的时间问题我就用线段树优化

    首先,题目要求是路径上的所有点的出边所指向的点都直接或间接与终点连通。

    我们可以先不考虑如何通过某点到达终点,我们想象如果通过一个点可以再到达终点,说明把边反过来后,终点可以到达这个点。

    那我们可以建反边,通过DFS求出可以去向终点的点了。到达不了的不符合条件,我们可以直接删点了。

    dfs:

    int vis[mn];//表示是否去过
    void dfs(int x){
        if(vis[x]) return; vis[x] = 1;
        for (int i = hh[x]; i; i=ee[i].nxt) if (!vis[ee[i].v])
                dfs(ee[i].v);
        //printf("%d
    ", x);
    }
    

    我们如何删点?

    因为我们最终还是要跑最短路,所以我们就可以把这条边边权开到不可能到达的长度。

    像这样

    	go(x, 1, n, 1) 
            if (!vis[x]) 
                for (int i = hh[x]; i; i = ee[i].nxt) {
                    int v = ee[i].v;
                    for (int j = h[v]; j; j = e[j].nxt)
                        e[j].w = 100000;
                }
    

    然后把反向的边变成正边(我是直接存的两种边,其实都一样),然后跑Dijkstra + 堆优化就好了。注意,如果我们把边权值变化后就不能拿bfs像原来一样那么做了

    代码:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <set>
    #include <stack>
    #include <string>
    #include <vector>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
    #define mn 10010
    #define mm 200010
    #define inf 2147483647
    #define ll long long
    #define ld long double
    #define fi first
    #define se second
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    //#define LOCAL
    #define mod 
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    //This is AC head above...
    struct edge{
        int f, v, w, nxt;
        edge(int _f = 0, int _v = 0, int _w = 1, int _nxt = 0) : f(_f), v(_v), w(_w), nxt(_nxt){}
    } e[mm << 1], ee[mm << 1];
    int p, h[mn],pp,hh[mn];
    inline void add(int a, int b, int c = 1){
        e[++p].nxt = h[a], h[a] = p, e[p].f = a, e[p].v = b, e[p].w = c;
    }
    inline void fadd(int a,int b){
        ee[++pp].nxt = hh[a], hh[a] = pp, ee[pp].f = a, ee[pp].v = b;
    }
    //Dij + 堆优化
    struct node{
        int u,v;
        bool operator <(const node &b) const{
            return u > b.u;
        }
    };//重载运算符
    int n,m,s,t;
    int dis[mn];//起点到每个点的距离
    priority_queue<node> q;//优先队列
    inline void Dij(int s){//s为起点
        go(i, 0, n, 1)
            dis[i] = inf;
        dis[s] = 0;
        node o;
        o.u = 0;o.v = s;
        q.push(o);
        while (q.size()){
            int u = q.top().v, d = q.top().u;
            q.pop();
            if(d!=dis[u])
                continue;
            rep(i,u){
                int v = e[i].v, w = e[i].w;
                if (dis[v] > dis[u] + w){
                    dis[v] = dis[u] + w;
                    node p;
                    p.u = dis[v], p.v = v;
                    q.push(p);
                }
            }
        }
    }
    int vis[mn];
    void dfs(int x){
        if(vis[x]) return; vis[x] = 1;
        for (int i = hh[x]; i; i=ee[i].nxt) if (!vis[ee[i].v])
                dfs(ee[i].v);
        //printf("%d
    ", x);
    }
    inline void debug(){
        go(i, 1, p, 1) printf("%d->%d %d
    ", e[i].f, e[i].v, e[i].w);
        go(i, 1, pp, 1) printf("%d->%d %d
    ", ee[i].f, ee[i].v, ee[i].w);
    }
    int main(){
        n = read(), m = read();
        go(i,1,m,1){
            int a = read(), b = read();
            fadd(b, a);
            add(a, b);
        }
        s = read(), t = read();
        //debug();
        dfs(t);
        go(x, 1, n, 1) 
            if (!vis[x]) 
                for (int i = hh[x]; i; i = ee[i].nxt) {
                    int v = ee[i].v;
                    for (int j = h[v]; j; j = e[j].nxt)
                        e[j].w = 100000;
                }
        //debug();
        Dij(s);
        if(dis[t]!=inf)
            cout << dis[t];
        else
            cout << -1;
    #ifdef LOCAL
        Debug("
    My Time: %.3lfms
    ", (double)clock() / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
    

    第十六次发题解,希望帮助同学们建立反向思维

  • 相关阅读:
    UIButtonIOS开发
    SharePoint Server 2007 SP1 已发布
    SharePoint 2007 External Binary Storage Component Preview 发布
    WSS 3.0 & MOSS 2007 SDK 1.1
    SharePoint工作流(ASP.NET表单版)教学视频
    Finally...
    Windows SharePoint Services 3.0 "Visual How Tos" 视频系列
    SharePoint 补丁
    在SharePoint Workflow中使用InfoPath Form的几个Tips
    对于Office Open XML文档格式,请发表您的看法
  • 原文地址:https://www.cnblogs.com/yizimi/p/10056277.html
Copyright © 2020-2023  润新知