弱联通分量
题目大意
给定一个有向图,判断是否对于任何两个点 ,,存在 或者 。
解题思路
定义:
若一张有向图的边替换为无向边后可以得到一张连通图,则称原来这张有向图是 弱连通的。
前置知识:
Tarjan
- 拓扑
- 缩点
缩点完之后一定是一个有向无环图,判断是否有两个及两个以上的节点的入度为 即可。
解题流程:
Tarjan
- 缩点
- 拓扑时判断是否有两个及两个以上的节点的入度为
- 输出
特别强调:多测不清空,亲人两行泪
AC CODE
阅读时请省略快读。
#include <bits/stdc++.h>
using namespace std;
/* --------------- fast io --------------- */ // begin
namespace Fastio
{
struct Reader
{
template <typename T>
Reader &operator>>(T &x)
{
char c = getchar();
T f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
x = 0;
while (c >= '0' && c <= '9')
{
x = x * 10 + (c - '0');
c = getchar();
}
x *= f;
return *this;
}
Reader &operator>>(char &c)
{
c = getchar();
while (c == ' ' || c == '\n')
{
c = getchar();
}
return *this;
}
Reader &operator>>(char *str)
{
int len = 0;
char c = getchar();
while (c == ' ' || c == '\n')
{
c = getchar();
}
while (c != ' ' && c != '\n' && c != '\r')
{ // \r\n in windows
str[len++] = c;
c = getchar();
}
str[len] = '\0';
return *this;
}
Reader() {}
} cin;
const char endl = '\n';
struct Writer
{
template <typename T>
Writer &operator<<(T x)
{
if (x == 0)
{
putchar('0');
return *this;
}
if (x < 0)
{
putchar('-');
x = -x;
}
static int sta[111];
int top = 0;
while (x)
{
sta[++top] = x % 10;
x /= 10;
}
while (top)
{
putchar(sta[top] + '0');
--top;
}
return *this;
}
Writer &operator<<(char c)
{
putchar(c);
return *this;
}
Writer &operator<<(char *str)
{
int cur = 0;
while (str[cur])
putchar(str[cur++]);
return *this;
}
Writer &operator<<(const char *str)
{
int cur = 0;
while (str[cur])
putchar(str[cur++]);
return *this;
}
Writer() {}
} cout;
} // namespace Fastio
#define cin Fastio ::cin
#define cout Fastio ::cout
#define endl Fastio ::endl
/* --------------- fast io --------------- */ // end
int T, n, m, cnt_node, cntn;
int cnt;
array<int, 2000005> head;
struct abc
{
int to, nxt;
};
array<abc, 2000005> dd;
int cnt_;
array<int, 2000005> head_, ind;
array<abc, 2000005> dd_;
array<bool, 2000005> vis;
array<int, 2000005> dfn, low, id;
stack<int> s;
queue<int> q;
inline void add(int u, int v)
{
dd[++cnt].to = v;
dd[cnt].nxt = head[u];
head[u] = cnt;
}
inline void add_(int u, int v)
{
dd_[++cnt_].to = v;
dd_[cnt_].nxt = head_[u];
head_[u] = cnt_;
}
inline void tarjan(int u)
{
dfn[u] = low[u] = ++cnt_node;
s.push(u);
vis[u] = 1;
for (int e = head[u]; e; e = dd[e].nxt)
{
if (!dfn[dd[e].to])
{
tarjan(dd[e].to);
low[u] = min(low[dd[e].to], low[u]);
}
else if (vis[dd[e].to])
low[u] = min(low[u], dfn[dd[e].to]);
}
if (low[u] == dfn[u])
{
cntn++;
while (1)
{
int now = s.top();
s.pop();
vis[now] = 0;
id[now] = cntn;
if (now == u) break;
}
}
}
void build()
{
for(int i = 1; i <= n; ++i)
for(int j = head[i]; j; j = dd[j].nxt)
{
int v = dd[j].to;
if(id[i] != id[v])
{
add_(id[i], id[v]);
ind[id[v]]++;
}
}
}
bool topu()
{
for(int i = 1; i <= cntn; ++i)
if(!ind[i])
{
q.push(i);
if(q.size() == 2) return false;
}
while(!q.empty())
{
int x = q.front();
q.pop();
for(int i = head_[x]; i; i = dd_[i].nxt)
{
int v = dd_[i].to;
ind[v]--;
if(!ind[v])
{
q.push(v);
if(q.size() == 2) return false;
}
}
}
return true;
}
void init()
{
cnt = 0;
head.fill(0);
cnt_ = 0;
head_.fill(0);
ind.fill(0);
cnt_node = 0;
cntn = 0;
dfn.fill(0);
low.fill(0);
id.fill(0);
vis.fill(0);
while(!s.empty()) s.pop();
while(!q.empty()) q.pop();
}
signed main()
{
cin >> T;
while(T--)
{
init();
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
int u, v;
cin >> u >> v;
add(u, v);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
build();
if(topu()) puts("Yes");
else puts("No");
}
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122156
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】