[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]);
}

猜你喜欢

转载自www.cnblogs.com/lijilai-oi/p/10720320.html