HDU 3594 Cactus 有向仙人掌图判定
题意
给出一个有向图,并给出仙人掌图的定义
- 图本身是强连通的
- 每条边属于且只属于一个环
判断输入的图是否是强连通的。
分析
杭电OJ上的数据比较弱,网上一些有明显错误的代码也能AC。
本着求真务实的精神,取网上查阅了相关资料,整理出来一个对自己来说还比较明确的算法。
从DFS森林说起
从有向图的某一点开始进行深度优先遍历,按照遍历的先后顺序会形成一棵树,像这种边被称作树边(Tree Edge)
当然有向图中还可能会存在一些其他的边:
- 从当前节点连向其祖先节点的边叫做反向边(Back Edge)
- 从当前节点连向其后代节点的边叫做前向边(Forward Edge)
- 从当前节点连向其他节点,可能是某个祖先其他分支的节点或者另一颗DFS树的节点,这种边叫做交叉边(Cross Edge)
按边的分类考虑仙人掌图
接下来默认图是强连通的,后面不再强调。
- 如果\(u \to v\)是一条前向边,必然有一条从\(v\)到\(u\)的路径\(Path\)。这样\(Path\)就和前向边\(u \to v\)构成了一个环,同时也和树边上的\(u\)到\(v\)的路径构成了一个环,而且这两个环有公共路径\(Path\)。因此得到结论:仙人掌图中不含前向边。
- 如果\(u \to v\)是一条交叉边,它们的最近公共祖先为\(anc\)。同样也有一条从\(v\)到\(anc\)的路径\(Path_{v \to anc}\),这条路径和\(v\)到\(anc\)的路径或相交或不相交。同样也构成了两个有公共边的环,因此得到结论:仙人掌图中不含交叉边。
因此,除了树边只剩下反向边,而且可以看出每有一条反向边\(u \to v\),它和树边上的路径\(v \to u\)构成了一个环。
下面想办法保证每条树边至多被一个环所包含:
- 一个点最多有一条反向边
- 在当前节点记录一个可以返回的最小的DFS序,保证反向边指向的节点的DFS序不能小于该值,否则会出现有公共边的两个环。
这是通过一遍DFS实现的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
using namespace std;
const int maxn = 10000 + 10;
int n, m;
vector<int> G[maxn];
stack<int> S;
int dfs_clock, pre[maxn], low[maxn];
int scc_cnt, sccno[maxn];
void dfs(int u) {
pre[u] = low[u] = ++dfs_clock;
S.push(u);
for(int v : G[u]) {
if(!pre[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
} else if(!sccno[v]) low[u] = min(low[u], pre[v]);
}
if(low[u] == pre[u]) {
scc_cnt++;
for(;;) {
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}
//Tarjan算法求强连通分量
void find_scc() {
dfs_clock = scc_cnt = 0;
memset(pre, 0, sizeof(pre));
memset(sccno, 0, sizeof(sccno));
for(int i = 0; i < n; i++) if(!pre[i])
dfs(i);
}
//第二遍DFS保证是仙人掌图
//color[u]为0表示还没有访问,为1表示正在访问,为2表示已经访问完毕
int color[maxn];
bool dfs2(int u, int minBack) { //minBack表示反向边能指向的最小的DFS序
color[u] = 1;
int backs = 0;//反向边的个数,至多只能有一个
for(int v : G[u]) if(color[v] == 1) { //找到一条反向边
backs++;
if(backs > 1) return false;
if(pre[v] < minBack) return false; //反向边指向的节点的DFS序小于最小值
}
if(backs) minBack = pre[u];
for(int v : G[u]) {
if(color[v] == 2) return false; //前向边或交叉边
if(color[v] == 0) //树边
if(!dfs2(v, minBack)) return false;;
}
color[u] = 2;
return true;
}
int main()
{
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) G[i].clear();
while(m--) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
}
find_scc();
if(scc_cnt > 1) { puts("NO"); continue; }
memset(color, 0, sizeof(color));
if(!dfs2(0, 0)) puts("NO");
else puts("YES");
}
return 0;
}
参考资料
1.仙人掌图分析
2.my solution注:这份代码没有考虑只能有一条反向边的限制,但也能在UVa上AC
HDU 3594 Cactus 有向仙人掌图判定的更多相关文章
- hdu 3594 Cactus /uva 10510 仙人掌图判定
仙人掌图(有向):同时满足:1强连通:2任何边不在俩个环中. 个人理解:其实就是环之间相连,两两只有一个公共点,(其实可以缩块),那个公共点是割点.HDU数据弱,网上很多错误代码和解法也可以过. 个人 ...
- hdu 3594 强连通好题仙人掌图,对自己的tarjan模板改下用这个
#include<stdio.h> #include<string.h> #define N 21000 struct node { int v,next; }bian[510 ...
- 仙人掌图判定及求直径HDU3594 BZOJ1023
https://wenku.baidu.com/view/ce296043192e45361066f575.html //仙人掌图基础知识3个判定条件 http://blog.csdn.net/y ...
- HDU 3594.Cactus 仙人掌图
Cactus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- HDU 3594 Cactus (强连通+仙人掌图)
<题目链接> <转载于 >>> > 题目大意: 给你一个图,让你判断他是不是仙人掌图. 仙人掌图的条件是: 1.是强连通图. 2.每条边在仙人掌图中只属于一个 ...
- HDU - 3594 Cactus
这是一个有向仙人掌的题目,要求判定给定的图是不是强连通图,而且每一条边只能出现在一个环中,这里有一个介绍有向仙人掌的文档:http://files.cnblogs.com/ambition/cactu ...
- HDU 3594 Cactus(仙人掌问题)
http://acm.hdu.edu.cn/showproblem.php?pid=3594 题意: 一个有向图,判断是否强连通和每条边只在一个环中. 思路: 仙人掌问题. 用Tarjan算法判断强连 ...
- hdu - 3594 Cactus (强连通)
http://acm.hdu.edu.cn/showproblem.php?pid=3594 判断给定的图是否是强连通的,并且每条边都只属于一个连通分量. 判断强连通只需要判断缩点之后顶点数是否为1即 ...
- HDU 3594 Cactus (强连通分量 + 一个边只能在一个环里)
题意:判断题目中给出的图是否符合两个条件.1 这图只有一个强连通分量 2 一条边只能出现在一个环里. 思路:条件1的满足只需要tarjan算法正常求强连通分量即可,关键是第二个条件,我们把对边的判断转 ...
随机推荐
- 【0 基础学Dojo】第【1】篇 HelloWord
打开dojo 官网首页 http://dojotoolkit.org/,我们看到 点击get dojo 你将得到下载Dojo 的不同方式 2,点击下面方式下载, 解压后 新建myTest.html, ...
- c#基础值类和引用类型
//值类型:int double char decimal bool enum struct //引用类型:string 数组 自定义类 集合 object 接口 值传递传递的值得本身 引用传递传递的 ...
- Java 面向对象,封装,继承
1相关概念的理解 1.1面向过程.面向对象 面向过程与面向对象都是编程中,编写程序的一种思维方式. 面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程.(职员思想) 面向 ...
- [转] java实现https请求
package com.lichmama.test.util; import java.io.ByteArrayOutputStream; import java.io.IOException; im ...
- w3c万维网的介绍和html基本构成
怎么与浏览器交互? 1.鼠标 2.键盘输入 w3c标准: 中文名:万维网联盟!外文名:world wide web cansortium万维网联盟创建于1994年,是web技术领域最具权威个影响的国际 ...
- 如何在github中的readme.md加入项目截图
1. 先在之前的本地项目文件夹里创建一个存放截图的文件夹.(如img文件夹) 2. 将新增的内容通过github desktop上传到github中 3. 在github中立马能看到刚刚上传的图片,打 ...
- socket tcp使用recv接收数据时,返回errno错误代码88
原因:就是recv函数的第一个参数不是可用的,也就是第一个参数不是建立连接时返回的文件描述符. 解决方法:xxx
- LR脚本中常用函数使用介绍
1.变量和参数的设置 //将IP地址和端口放入到参数中lr_save_string("192.168.1.133:8081","ip"); //计算变量数组的元 ...
- SqlServer中提示和报错信息的翻译
有时候遇到SqlServer一些报错需要上网查找解决方法,一些比较生僻的问题汉语搜索往往得不到想要的,就要使用英文在外网搜索.之前都是自己尝试翻译,或者使用错误码,或者找个英文版的数据库重现问题.有时 ...
- input输入大于0的小数和整数
<input onkeyup="num(this)"onbeforepaste="num(this)"> <script src='jquer ...