洛谷P2296-寻找道路【日常图论,最短路,SPFA】

题目

一个有向图,要求满足要求的最短路径,要求为:

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

输入1

3 2 (3个点,2条边)
1 2 (1和2之间可以连接)
2 1
1 3 (从1到3)

输出1

-1
这里写图片描述

输入2

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

输出2

3
这里写图片描述


解题思路

其实我们就求出满足要求的点,然后在这些点里找最短路,还有本人这里的方法比较复杂和麻烦


代码

#include<cstdio>
using namespace std;
struct woc{
    int next,x,y;
};//日常邻接表
woc a[200001],lt[200001];
int xx,yy,n,m,k,state[10001],ls[10001],t,head,tail,f[10001],star,over;
int fls[10001];
bool ltfl[10001];
bool v[10001];
void check()//求所有可以直接或间接到终点的边
{
    int t=0;
    int head=0;
    int tail=1;
    state[1]=over;
    ltfl[state[1]]=true;//初始化
    while (head!=tail)
    {
        head++;
        head=(head-1)%n+1;
        t=fls[state[head]];//求边
        while (t!=0)
        {
            if (!ltfl[lt[t].y])
            {
                tail++;
                tail=(tail-1)%n+1;
                state[tail]=lt[t].y;
                ltfl[lt[t].y]=true;//标记
            }
            t=lt[t].next;//求下一条边
        }
    }
}
bool ok(int x)//是否满足要求
{
    int t=ls[x];
    while (t!=0)
    {
        if (!ltfl[a[t].y]) return false;
        t=a[t].next;
    }
    return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    state[1]=1;
    int u=0;    
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&xx);
        scanf("%d",&yy);
        a[++u].next=ls[xx];
        ls[xx]=u;
        a[u].x=xx;
        a[u].y=yy;//边
        lt[u].next=fls[yy];
        fls[yy]=u;
        lt[u].y=xx;
        lt[u].x=yy;//记录一条回去的边
    }   
    scanf("%d%d",&star,&over);
    for (int i=1;i<=n;i++) f[i]=2147483647;//初始化    
    check();//求所有可以直接或间接到终点的边
    head=0;
    tail=1;
    state[1]=star;
    v[state[1]]=true;
    f[star]=0;//初始化×2
    while (head!=tail)
    {
        head++;//出队
        head=(head-1)%n+1;//循环队列
        t=ls[state[head]];
        while (t!=0)
        {
            if (f[a[t].x]+1<f[a[t].y] && ok(a[t].y))//判断是否满足要求
            {
                f[a[t].y]=f[a[t].x]+1;//松弛
                if (!v[a[t].y])
                {
                    tail++;//入队
                    tail=(tail-1)%n+1;//循环队列
                    state[tail]=a[t].y;
                    v[a[t].y]=true;
                }
            }
            t=a[t].next;//下一条边
        }
        v[state[head]]=false;//解封
    }
    if (f[over]==2147483647) printf("-1");//是否有解
    else printf("%d\n",f[over]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值