• POJ-2762 Going from u to v or from v to u?


    题目大意:

    给出一个有向图,这个图,是否存在任意两点a,b可达,这里的任意两点a,b可达是说,只要从a能到b或者只要能从b到a就算是可达的。

    解题思路:

    先求出这个图的强连通分量,然后缩点建图,只要这个图是一条链状的,那么就可以满足任意两点都可达,否则不满足。

    原因是只要这个缩点建图之后的图是链状的,那么必然从链的头到尾,任意两点都可达。一旦不是链状,要么出现分叉,要么某个点入度>=2,这种情况在分叉的两端都是无法可达的。所以只需要是链状就可以了。这个可以用拓扑排序来做,也可以直接一遍dfs求出。

    代码:

    #include <stack>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef struct node {
    	int v, nxt;
    	node(int a = 0, int b = 0) {
    		v = a; nxt = b;
    	}
    }Edge;
    
    const int maxn = 1005;
    const int maxm = 12010;
    
    int n, m;
    stack<int> s;
    Edge edge[maxm];
    int ComponetNumber;
    int tot, head[maxn];
    int inComponet[maxn];
    vector<int> vec[maxn];
    int inx, inStack[maxn];
    int low[maxn], dfn[maxn];
    vector<int> Componet[maxn];
    int in[maxn], out[maxn], vis[maxn];
    
    void init() {
    	inx = tot = ComponetNumber = 0;
    	while (!s.empty()) s.pop();
    	memset(in, 0, sizeof(in));
    	memset(dfn, 0, sizeof(dfn));
    	memset(low, 0, sizeof(low));
    	memset(out, 0, sizeof(out));
    	memset(vis, 0, sizeof(vis));
    	memset(head, -1, sizeof(head));
    	memset(inStack, 0, sizeof(inStack));
    	for (int i = 0; i < maxn; ++i) {
    		vec[i].clear();
    		Componet[i].clear();
    	}
    }
    void add(int u, int v) {
    	edge[tot] = Edge(v, head[u]);
    	head[u] = tot++;
    }
    void tarjan(int x) {
    	dfn[x] = low[x] = ++inx;
    	inStack[x] = 2;
    	s.push(x);
    
    	for (int i = head[x]; ~i; i = edge[i].nxt) {
    		int v = edge[i].v;
    		if (!dfn[v]) {
    			tarjan(v);
    			low[x] = min(low[x], low[v]);
    		} else if (inStack[v] == 2) {
    			low[x] = min(low[x], dfn[v]);
    		}
    	}
    
    	if (dfn[x] == low[x]) {
    		++ComponetNumber;
    		while(!s.empty()){
    			int v = s.top(); s.pop();
    			inStack[v] = 1;
    			Componet[ComponetNumber].push_back(v);
    			inComponet[v] = ComponetNumber;
    			if (v == x) break;
    		}
    	}
    }
    void dfs(int p) {
    	vis[p] = 1;
    	int len = vec[p].size();
    	for (int i = 0; i < len; ++i) {
    		if (!vis[vec[p][i]]) dfs(vec[p][i]);
    	}
    	if (len > 1) vis[p] = 0;
    }
    int main() {
    	ios::sync_with_stdio(false); cin.tie(0);
    	int a, b, t; cin >> t;
    	while (t--) {
    		cin >> n >> m; init();
    		for (int i = 0; i < m; ++i) {
    			cin >> a >> b;
    			add(a, b);
    		}
    		for (int i = 1; i <= n; ++i) {
    			if (!dfn[i]) tarjan(i);
    		}
    		for (int i = 1; i <= n; ++i) {
    			for (int j = head[i]; ~j; j = edge[j].nxt) {
    				int v = edge[j].v;
    				if (inComponet[i] != inComponet[v]) {
    					++in[inComponet[v]];
    					++out[inComponet[i]];
    					vec[inComponet[i]].push_back(inComponet[v]);
    				}
    			}
    		}
    		for (int i = 1; i <= ComponetNumber; ++i) {
    			if (!in[i]) { dfs(i); break; }
    		}
    		int flag = 1;
    		for (int i = 1; i <= ComponetNumber; ++i) {
    			if (!vis[i]) flag = 0;
    		}
    		if (flag) cout << "Yes
    ";
    		else cout << "No
    ";
    	}
    	return 0;
    }


  • 相关阅读:
    无重叠区间
    ARC109E 1D Reversi Builder
    IOI2021集训队作业129CF Longest Rivers
    IOI2021集训队作业281CA Balanced Diet
    IOI2021集训队作业227CB Branch Assignment
    IOI2021集训队作业277BK Tours
    IOI2021集训队作业125AA Baggage
    6894. 【2020.11.25提高组模拟】小 S 埋地雷 (loj6611. 摧毁时间线)
    ARC108 题解&总结
    HTML教程
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179370.html
Copyright © 2020-2023  润新知