• [Luogu P2296][NOIP 2014]寻找道路


    emmm交了第8次才过。

    这道题目测一道单源最短路问题,因此dijkstra或者spfa板子先准备好。因为题中对最短路有限定:

    1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
    2. 在满足条件1的情况下使路径最短。

    而题中还说“题目保证终点没有出边。”,所以我们考虑反向处理,也就是说最短路径上的点一定在以终点为根的搜索树上,并且这些点的所有出边一定也在这棵树上。所以考虑dfs/bfs搜索图,标记所有搜过的点,然后枚举每个标记点的出边所指向的点,如果不在树上则删除标记。这里有一个坑点,如果直接对标记进行修改,由于树上的编号和搜索顺序没有关系,会导致改标记的时候把没扫到的点也改掉了,从而造成删掉不该删掉的点,因此考虑备份标记即可。

    然后我错这么多次的原因,说起来非常水,原因是在spfa的时候没有对入队的元素标记,数据大的时候入队多次直接爆空间,只有第一个点数据小能水10分QAQ

    参考代码:

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define N 10010
    #define M 200010
    #define inf 1e8
    using namespace std;
    queue<int>q;
    int nxt[M],to[M],fnxt[M],fto[M];
    int n,m,in_q[N],head[N],vis[N],fhead[N],fcnt,cnt,visited[N],dis[N],s,t;
    void dfs(int x)
    {
        visited[x] = 1;
        for(int i = fhead[x];i;i = fnxt[i])
        {
            if(!visited[fto[i]]) dfs(fto[i]);
        }
    }
    void spfa()
    {
        for(int i = 1;i <= n;i++) dis[i] = inf;
        in_q[s] = 1;
        dis[s] = 0;
        q.push(s);
        int u;
        while(!q.empty())
        {
            u = q.front();
            q.pop();
            in_q[u] = 0;
            if(!visited[u]) continue;
            for(int i = head[u];i;i = nxt[i])
            {
                if(dis[to[i]] > dis[u] + 1)
                {
                    dis[to[i]] = dis[u] + 1;
                    if(!in_q[to[i]])
                    {
                        in_q[to[i]] = 1;
                        q.push(to[i]);
                    }
                }
            }
        }
    }
    void del()
    {
        for(int i = 1;i <= n;i++) vis[i] = visited[i];
        for(int i = 1;i <= n;i++)
        {
            if(!vis[i]) 
            {
                for(int j = fhead[i];j;j = fnxt[j])
                {
                    if(vis[fto[j]]) visited[fto[j]] = 0;
                }
            }
        }
    }
    
    void add(int u,int v,int k)
    {
        if(k == 1)
        {
            to[++cnt] = v;
            nxt[cnt] = head[u];
            head[u] = cnt;
        }
        else
        {
            fto[++fcnt] = v;
            fnxt[fcnt] = fhead[u];
            fhead[u] = fcnt;
        }
        return;
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        int u,v;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d %d",&u,&v);
            add(u,v,1);
            add(v,u,0);
            
        }
        scanf("%d %d",&s,&t);
        dfs(t);
        del();
        spfa();
        printf("%d",(dis[t] >= inf) ? -1 : dis[t]);
    }
  • 相关阅读:
    linux网络编程-socket(36)
    linux网络编程-socket(2)
    linux网络编程-socket(1)
    jni不通过线程c回调java的函数
    jni 字符串的梳理 2 字符串的处理操作
    jni 字符串的梳理
    android studio 中jni底层日志的打印
    事件冒泡与事件捕获
    盒子模型
    比较好的前端面试题
  • 原文地址:https://www.cnblogs.com/lijilai-oi/p/10720320.html
Copyright © 2020-2023  润新知