连通性查询

【题目描述】
在一个有向无权图中,给定N个点和M条边,有Q次询问,询问两点是否连通。
【输入格式】
第一行两个整数n(0< n <= 8000), m(0 < m <= 16000)分别代表顶点数和边数;
接下来有m行,每行一对整数u, v(0 < u, v < n),表示点u, v之间有一条从u指向v的路径;
接下来一个整数q(q <= 10000),表示有q组查询;
每组查询两个整数f, t(0 < f, t < n )表示询问是否有一条f指向t的路径;
【输出格式】
一共q行,每一样一个 “YES”或“NO”(均为大写,不含引号)表示是否有一条f指向t的路径
【样例输入】
5 5
1 3
1 5
2 5
2 4
3 2
3
1 2
3 4
1 4
【样例输出】
YES
YES
YES
【分析】
如果写暴力算法,Floyd应该没问题吧,但是对于这题显然超时。
加了优化的Dijkstra和Spfa都会超时(如果不信可以试试嘛)。
那接下来就是正解部分。
我们用Tarjan算法求出所有的环,将图中的环缩成一个点(即缩点法),然后把图转换成一个DAG,再双向广搜即可。
不求环,直接双向广搜能不能过呢?(应该)是可以的,感兴趣的同学可以自行验证(滑稽)。
如果是随机数据,搞出很多个环的可能性是很大的,所以缩点之后用dfs也可以刷掉,反正我用的dfs(众:只用dfs这代码长度都1700B+了,再来个广搜是要2KB+吗)。
按照套路,炒鸡辣鸡的博主在缩点完成之后根本不会写深搜了, 于是随便搞了个bitset凑数吧,没想到代码竟然过了23333!
好了,重要的部分已经说完了,剩下就是搜代码敲代码的事咯~
给出floyd的代码:

#include<bits/stdc++.h>
using namespace std;
int a[2010][2010]={0};
int n,m,q,x,y;
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        a[x][y]=1;
    }
    for (int k=1;k<=n;k++)
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                if (!a[i][j] && a[i][k] && a[k][j]) a[i][j]=1;
    scanf("%d",&q);
    for (int i=1;i<=q;i++){
        scanf("%d%d",&x,&y);
        if (a[x][y]) printf("YES\n"); else printf("NO\n");
    }
}

想要博主的代码请支付100软妹币23333

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值