图找环
如标题所示,本文主要探讨无向图/有向图中环的做法
1. 拓扑排序判断环是否存在
在一个途中,如果点i
和点j
之间存在一条路径,则认为这两个点相互依赖, 而在拓扑序中每个点只会和后面的点产生依赖关系,由此可知如果图中存在环那么一定不存在拓扑序
那么应该如何求拓扑序呢?
bool toposort() {
vector<int> L;
queue<int> S;
for (int i = 1; i <= n; i++)
if (in[i] == 0) S.push(i); // in[]存的入度,如果是无向图则让度<=1 的入队
while (!S.empty()) {
int u = S.front();
S.pop();
L.push_back(u);
for (auto v : G[u]) {
if (--in[v] == 0) {
S.push(v);
}
}
}
if (L.size() == n) {
for (auto i : L) cout << i << ' ';
return true;
} else {
return false;
}
}
2. 并查集判断环的个数
我们每向图中添加一条边(u, v)时,如果u
和 v
已经在集合当中则说明u, v
可以借助集合中某点x
形成依赖关系,然而(u, v)本身就有依赖关系,那么(u, v, x)形成一个环
inline void solve()
{
int n, m; cin >> n >> m;
DSU dsu(n + 1);
int ans = 0;
for (int i = 0; i < m; i++)
{
int a, b; cin >> a >> b;
if (!dsu.merge(a, b)) ans++; // 如果是有向图则判断find(u) == v, 不成环就merge(v, u)
}
cout << ans << endl;
}
3. 暴力循环判断环的长度(只有一个出度的情况)
例题,因为按照题意图中一定有环,所以就没事先判断环是否存在
存在环的话,可以从一个点一直往前走,如果有一个点被走了两次那么它一定在环里面
inline void solve()
{
int n, k; cin >> n >> k;
std::vector<int> adj(n + 1);
int flag = 0;
for (int i = 1; i <= n; i++)
{
cin >> adj[i];
if (i == adj[i]) flag++;
}
if (k == 1)
{
string s = flag == n ? "Yes" : "No";
cout << s << endl;
return;
}
vector<int> cnt(n + 1, 0);
vector<bool> st(n + 1);
for (int i = 1; i <= n; i++)
{
if (cnt[i] != 0) continue;
int a = i;
while (!cnt[a])
{
cnt[a] = 1;
a = adj[a];
}
if (cnt[a] == 1 && !st[a]) // 这个环已经没走过,cnt[a] = 2 说明之前走过
{
int t = 1;
int nx = adj[a];
while (a != nx)
{
t++;
nx = adj[nx];
}
if (t != k)
{
cout << "No" << endl;
return;
}
}
for (int j = i; !st[j]; j = adj[j]) // 将已经走过的路经打标记
{
st[j] = true;
}
}
cout << "Yes" << endl;
}
本文作者:自动机
本文链接:https://www.cnblogs.com/monituihuo/p/17628789.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步