[SMOJ1830]小岛
来源:互联网 发布:义乌样品淘宝拍摄 编辑:程序博客网 时间:2024/04/28 06:39
题目描述
有
N 个城市,编号 1 至N ,农夫 FJ 为这N 个城市共设计了M 条单向飞机航班。
如果存在两个不同的城市a 和b ,使得城市a 无论如何也无法到达城市b (即使转机也不能到达b ),而且城市b 无论如何也无法到达城市a (即使转机也不能到达a ),
那么我们认为 FJ 设计的这M 条飞机航班是不合理的,输出”No”,否则输出“Yes”。
输入格式 1830.in
多组测试数据。
第一行,一个整数R ,表示有R 组测试数据。
每组测试数据格式:
第一行,两个整数,N 和M 。1≤N≤50000 ,1≤M≤60000 。
接下来有M 行,每行两个整数:a 和b ,表示城市a 有一条单向航班飞向城市b 。
输出格式 1830.out
共
R 行,每行输出Yes或者No。
输入样例 1830.in
1
3 3
1 2
2 3
3 1
输出样例 1830.out
Yes
题意:有
如果题目条件是“
但是,显然缩点这一步并不是没有用的。缩点后同一强连通分量内的点肯定互相可达,因此只需要判断强连通分量之间是否可达就可以了。
我们不妨这样来思考:把缩点后得到的 DAG 中结点编号为 1~
那么,我们考虑第
同理,对于第
可能会问,这样一来,仅仅是满足了相邻结点之间连通的要求而已。但其他的呢?事实上,只要能够满足相邻结点之间连通,任意两个结点之间就一定连通。
归纳起来,也就是说,要求缩点后得到的是一条链!但是,除了相邻结点中的边之外,可能存在其他多余的边。那无所谓,只要成一条链,已经足够满足要求。
具体的实现:缩点可以在
lgj 也在评讲的时候告诉我们:赛场上思考问题往往不一定能够立即得到正解,因此要多举例,画图(或列式?)分析,找到一些共通点,从而突破。
参考代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <stack>#include <queue>using namespace std;const int maxn = 1e5 + 100;const int maxm = 1e5 + 100;struct Edge { int to, next; } edge[maxm];int a[maxm], b[maxm];int n, m;int head[maxn], belong[maxn];int cntEdge, cntScc;void addEdge(int u, int v) { edge[++cntEdge].to = v; edge[cntEdge].next = head[u]; head[u] = cntEdge;}int dfn[maxn], low[maxn], timeStamp;bool instack[maxn];stack <int> st;int inDegree[maxn];void tarjan(int root) { dfn[root] = low[root] = ++timeStamp; instack[root] = true; st.push(root); for (int i = head[root]; i; i = edge[i].next) if (!dfn[edge[i].to]) { tarjan(edge[i].to); low[root] = min(low[root], low[edge[i].to]); } else if (instack[edge[i].to]) low[root] = min(low[root], dfn[edge[i].to]); if (dfn[root] == low[root]) { cntScc++; int cur; do { cur = st.top(); st.pop(); instack[cur] = false; belong[cur] = cntScc; //每个结点属于缩点后的哪个强连通分量 } while (cur != root); }}bool topo() { queue <int> q; while (!q.empty()) q.pop(); for (int i = 1; i <= cntScc; i++) if (!inDegree[i]) q.push(i); //将入度为 0 的点入队 if (q.size() > 1) return false; //如果一次有多个点同时入队,则它们之间就互不可达,整个图不合法 while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = head[cur]; i; i = edge[i].next) if (!(--inDegree[edge[i].to])) q.push(edge[i].to); if (q.size() > 1) return false; //同上 } return true;}int main(void) { freopen("1830.in", "r", stdin); freopen("1830.out", "w", stdout); int r; scanf("%d", &r); while (r--) { scanf("%d%d", &n, &m); memset(head, 0, sizeof head); cntEdge = 0; for (int i = 0; i < m; i++) { scanf("%d%d", &a[i], &b[i]); addEdge(a[i], b[i]); } memset(dfn, 0, sizeof dfn); timeStamp = 0; memset(instack, false, sizeof instack); cntScc = 0; for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); memset(head, 0, sizeof head); cntEdge = 0; memset(inDegree, 0, sizeof inDegree); for (int i = 0; i < m; i++) if (belong[a[i]] != belong[b[i]]) { addEdge(belong[a[i]], belong[b[i]]); ++inDegree[belong[b[i]]]; } puts(topo() ? "Yes" : "No"); } return 0;}
- [SMOJ1830]小岛
- 小岛梦
- 死亡小岛
- 小岛面积
- 连接小岛
- 小岛问题
- 【字符串】转自小岛
- 小岛和雷达
- 舟山群岛小岛攻略
- 小岛场景搭建
- [SMOJ1831]小岛II
- 二维数组寻找小岛
- AHOI 2015 小岛
- 待字闺中之死亡小岛分析
- 贪心 51Nod1460 连接小岛
- 51Nod-1460-连接小岛
- 51nod-1460 连接小岛
- vijos1942——小岛 Floyed
- CodeForces 637 C.Promocodes with Mistakes(水~)
- QMUI / QMUI_iOS框架学习(六)
- list map set区别
- 走进处理器核设计
- 【LeetCode】9. Palindrome Number
- [SMOJ1830]小岛
- Hadoop的经验小结:MapWritable的使用以及别的细节
- 关于ajax中后台与前端之间传json的问题
- Java进阶(七)Java加密技术之非对称加密算法RSA
- PLSQL连接本地的Oracle数据库 (这篇blog主要是针对新手,我也是个新手)
- HTML5标签
- linux使用频率较高的shell命令
- 题目1014:排名 九度OJ
- ios 3dTouch----详细