弱联通分量

Going from u to v or from v to u (poj2762)

损坏的传送门

题目大意

给定一个有向图,判断是否对于任何两个点 u u u v v v,存在 u → v u \to v uv 或者 v → u v \to u vu

解题思路

定义:

若一张有向图的边替换为无向边后可以得到一张连通图,则称原来这张有向图是 弱连通的。

前置知识:

  • Tarjan
  • 拓扑
  • 缩点

缩点完之后一定是一个有向无环图,判断是否有两个及两个以上的节点的入度为 0 0 0 即可。

解题流程:

  1. Tarjan
  2. 缩点
  3. 拓扑时判断是否有两个及两个以上的节点的入度为 0 0 0
  4. 输出

特别强调:多测不清空,亲人两行泪

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值