• 【NOIP2014提高组T5】寻找道路-双spfa


    (本人本题完成于2016-7-19)

    题目大意:给一个有向图,每条边的权值为1,求是否存在一条从点s到点t的路径使得路径上的每一个点的出边所指的点都存在到t的路径,如果有,输出最短路径长度,否则输出-1。

    做法:由于点数N很大(可达10000),所以要用邻接表存储有向图。在读入边时,顺便存一个反图,对该反图以t为起点做一遍spfa,找到不存在到t的路径的点(即在反图中由t不能到达的点),再将这些点和反图中这些点所指向的点(即正图中有出边指向这些点的点)标记上,再对正图以s为起点做一遍spfa,避开标记过的点(即不能在路径中出现的点),就能得出答案了。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #define inf 99999999
    using namespace std;
    int n,m,s,t,total=0,last[10010]={0},flast[10010]={0};
    bool vi[10010]={0};
    struct edge
    {
      long v,next;
    }g[220010],fg[220010]; //数组模拟链表,用邻接表存储有向图,g为正图,fg为反图
    
    void readg(int i,int j) //往正图中加入边(i,j)
    {
      g[last[i]].next=total;
      g[total].v=j;
      g[total].next=0;
      last[i]=total;
    }
    
    void readfg(int i,int j) //往反图中加入边(i,j)
    {
      fg[flast[i]].next=total;
      fg[total].v=j;
      fg[total].next=0;
      flast[i]=total;
    }
    
    void input()
    {
      scanf("%d %d",&n,&m);
      for(int i=1;i<=n;i++)
      {
        last[i]=i;
    	flast[i]=i;
    	g[i].next=0;g[i].v=i;
    	fg[i].next=0;fg[i].v=i;
    	total++;
      }
      for(int i=1;i<=m;i++)
      {
        int x,y;
    	scanf("%d %d",&x,&y);
    	total++;
    	readg(x,y);
    	readfg(y,x);
      }
      scanf("%d %d",&s,&t);
    }
    
    void fspfa()
    {
      bool d[10010]={0};
      queue <int> q;
      q.push(t);d[t]=1;
      while(!q.empty())
      {
        int h=q.front(),i;
    	q.pop();
    	i=h;
    	while(i!=0)
    	{
    	  if (!d[fg[i].v]) {q.push(fg[i].v);d[fg[i].v]=1;} //如果该点没访问过,将其插入队列
    	  i=fg[i].next;
    	}
      }
      for(int i=1;i<=n;i++) //标记路径中不能包含的点
        if (!d[i])
    	{
    	  int j=i;
    	  while(j!=0)
    	  {
    	    vi[fg[j].v]=1;
    	    j=fg[j].next;
    	  }
    	}
    }
    
    void spfa()
    {
      int d[10010];
      queue <int> q;
      q.push(s);d[s]=0;
      if (vi[s]) {printf("-1");return;}
      for(int i=1;i<=n;i++) if (i!=s) d[i]=inf;
      while(!q.empty())
      {
        int h=q.front(),i;
    	q.pop();
    	i=h;
    	while(i!=0)
    	{
    	  if (!vi[g[i].v]&&d[h]+1<d[g[i].v]) {q.push(g[i].v);d[g[i].v]=d[h]+1;} //做spfa时避开不能包含的点
    	  i=g[i].next;
    	}
      }
      if (d[t]!=inf) printf("%d",d[t]);
      else printf("-1");
    }
    
    int main()
    {
      input();
      fspfa();
      spfa();
      
      return 0;
    }

  • 相关阅读:
    __proto__、prototype、constructor 之间的关系
    call()与apply()区别
    条件注释判断浏览器
    永远在页面底部的层
    jQuery1.9和jQuery2.0加载(IE10下条件判断失效)
    mousewheel
    2013多校第四场 G题 ZZ的搬砖难题
    hdu 4389 x mod f(x) 数位DP
    hdu 4468 spy 构造kmp
    hdu 4466 triangle 三角形统计 数学计数
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9794027.html
Copyright © 2020-2023  润新知