【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;
}

posted @ 2016-07-19 19:08  Maxwei_wzj  阅读(133)  评论(0编辑  收藏  举报