codevs 3731 寻找道路

题目描述 Description

在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

1.路径上的所有点的出边所指向的点都直接或间接与终点连通。

2.在满足条件1的情况下使路径最短。

注意:图G中可能存在重边和自环,题目保证终点没有出边。

请你输出符合条件的路径的长度。


输入描述 Input Description

第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。

接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。

最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。


输出描述 Output Description

输出文件名为road.out。

输出只有一行,包含一个整数,表示满足题目述的最短路径的长度。如果这样的路径不存在,输出-1。

   建反边真是一个好强大的技能。

    首先,我们可以反向进行建边,以终点为起点bfs出每一条边的连通性,将反向能够连过的边的vis记为1。

    接着,以起点为起点正着进行bfs,在添加now连接新的边i 进入队列之中需满足now连的所有边vis都不为0,即没有边与终点不连通,这样即可保证所有点的出边所指向的点都直接或间接与终点连通。注意一定要将重点的vis改为一个不为1的数,否则无法搜索到终点。

    下附AC代码。

#include<iostream>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<string.h>
#define maxn 10005
using namespace std;
int vis[maxn];
int n,m;
int f,t;
vector<int> zb[maxn];
vector<int> fb[maxn];
int cnt=0;
struct nod
{
	int now,dis;
	nod(int a,int b)
	{
		now=a;
		dis=b;
	}
	nod(){}
};
queue<nod> q;
queue<nod> rq;
int num[maxn];
int dis[maxn];
void jianfanbian()
{
	rq.push(nod(t,0));
	vis[t]=1;
	while(!rq.empty())
	{
		nod now=rq.front();
		rq.pop();
		num[now.now]=now.dis;
		for(int i=0;i<fb[now.now].size();i++)
		{			
			if(vis[fb[now.now][i]]==0)
			{
				rq.push(nod(fb[now.now][i],now.dis+1));
				vis[fb[now.now][i]]=1;
			}
		}
	}
	num[t]=-1;
}
void qiuzhengjie()
{
	memset(vis,0,sizeof(vis));
	dis[f]=0;
	vis[f]=1;
	q.push(nod(f,0));
	while(!q.empty())
	{
		nod now=q.front();		
		q.pop();
		
		bool flag=true;
		
		for(int i=0;i<zb[now.now].size();i++)
		{
			if(num[zb[now.now][i]]==0)
			{
				flag=false;
				break;
			}
		}
		
		if(flag==false)
		continue;
		
		dis[now.now]=now.dis;
		
		for(int i=0;i<zb[now.now].size();i++)
		{
			if(vis[zb[now.now][i]]==0)
			{
				q.push(nod(zb[now.now][i],now.dis+1));
				vis[zb[now.now][i]]=1;
			}
		}
		if(dis[t])
		{
			cout<<dis[t]<<endl;
			exit(0);
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		zb[a].push_back(b);
		fb[b].push_back(a);
	}
	cin>>f>>t;
	jianfanbian();
	qiuzhengjie();
	cout<<-1<<endl;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值