zoukankan      html  css  js  c++  java
  • 【题解】洛谷P2296 [NOIP2014TG] 寻找道路(SPFA+DFS)

    题目来源:洛谷P2296

    思路

    一开始看还以为是一道水题 虽然本来就挺水的

    本道题的难点在于如何判断是否路径上的点都会直接或者间接连着终点

    我们需要在一开始多建一个反向图

    然后从终点DFS回去 把路径上的点标记

    DFS完之后遍历所有的点 如果当前点没有被标记 说明其不会直接或者间接连着终点

    那么我们只需要把没有被标记的点在反向图中到达的点(也就是正向图中到达这个点的前一个点)标记为不计算在图内

    PS:这里的标记数组要另外再建一个 如果直接改前面的数组会因为没有更新完就修改而多删除有用的点

    这样我们就把所有的不需要遍历的点删除了

    最后就是SPFA解决

    代码

    #include<iostream>
    #include<queue>
    using namespace std;
    #define maxn 100010 
    queue <int> q;
    int n,m,cnt2,cnt1,t,w,start,end;
    int h1[maxn],h2[maxn],dis[maxn];
    bool f[maxn],vis[maxn],vis1[maxn];//f为spfa的判断 vis为反向图的判断 vis1删除点的判断 
    struct Edge
    {
        int to;
        int next;
    }e1[maxn*20],e2[maxn*20];
    void add1(int u,int v)
    {
        e1[++cnt1].to=v;
        e1[cnt1].next=h1[u];
        h1[u]=cnt1;
    }
    void add2(int u,int v)
    {
        e2[++cnt2].to=v;
        e2[cnt2].next=h2[u];
        h2[u]=cnt2;
    }
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=h2[u];i;i=e2[i].next)
        {
            int v=e2[i].to;
            if(!vis[v]) dfs(v);
        }
    }
    void spfa()//常规spfa 
    {
        for(int i=1;i<=n;i++) dis[i]=1e9+7;
        q.push(start);
        f[start]=1;
        dis[start]=0;
        while(!q.empty())
        {
            int temp=q.front();
            q.pop();
            f[temp]=0;
            if(!vis[temp]) continue;
            for(int i=h1[temp];i;i=e1[i].next)
            {
                int v=e1[i].to;
                if(dis[v]>dis[temp]+1)
                {
                    dis[v]=dis[temp]+1;
                    if(!f[v])
                    {
                        f[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            cin>>x>>y;
            add1(x,y);//正向图 
            add2(y,x);//反向图 
        }
        cin>>start>>end;
        dfs(end);//从终点DFS 
        for(int i=1;i<=n;i++)//把不用的点删去 
        {
            if(!vis[i])
            for(int j=h2[i];j;j=e2[j].next)
            {
                int v=e2[j].to;
                vis1[v]=1;//更改新建的数组 
            }
        }
        for(int i=1;i<=n;i++)
            if(vis1[i]==1) vis[i]=0;//更改不用遍历的点 
        spfa();
        if(dis[end]==1e9+7)
        cout<<-1;
        else
        cout<<dis[end];
    }
  • 相关阅读:
    欢乐送小程序自动化探索实践
    看完这篇还不了解 Nginx,那我就哭了!
    测试人的技术栈
    Bug,项目过程中的重要数据
    什么是测试开发工程师?
    hdu 1219 AC Me
    hdu 1202 The calculation of GPA(算绩点问题)
    hdu1205吃糖果(插空法)
    hdu1201(18岁生日)
    hdu1231最大连续子序列
  • 原文地址:https://www.cnblogs.com/BrokenString/p/9858861.html
Copyright © 2011-2022 走看看