连通性查询

来源:互联网 发布:androidndkr10e mac 编辑:程序博客网 时间:2024/06/08 18:25

【题目描述】
在一个有向无权图中,给定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

原创粉丝点击