zoukankan      html  css  js  c++  java
  • [题解] uva 10510 cactus (tarjan强连通分量)

    - 传送门 -

     https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1451

    # 10510 - Cactus Time limit: 3.000 seconds |

    | Root | Submit Problem Stats
    uDebug Download as PDF |

    (题面见PDF)

      ### - 题意 -  判断给出的图是不是仙人掌:  定义: 整个图为一个强连通分量, 任何一条边不在两个环中.   ### - 思路 -  当我们DFS的时候, 搜到一个已在栈中的点 v 就说明出现了一个环, 我们把环上的节点(除了 v )都打一个标记, 当有一个点的标记超过一个时, 说明它出现在两个环中, 同时判断图中强连通分量的个数.  用DFS树来脑补的话可能可以稍微理解一点儿???    细节见代码.    PS:  考tarjan的理解的时候到了.  但我并没有理解.  ......

    - 代码 -

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 1e4 + 5;
    
    bool INSTK[N];
    int STK[N], DFN[N], LOW[N];
    int TO[N], HD[N], NXT[N];
    int CNT[N], F[N];
    int T;
    int sz, tp, tot, scc_num;
    int n, m, ans;
    
    void init() {
    	ans = 1;
    	sz = tp = tot = scc_num = 0;
    	memset(CNT, 0, sizeof (CNT));
    	memset(F, 0, sizeof (F));
    	memset(DFN, 0, sizeof (DFN));
    	memset(HD, 0, sizeof (HD));
    	memset(INSTK, false, sizeof (INSTK));
    }
    
    void add(int x, int y) {
    	TO[++sz] = y; NXT[sz] = HD[x]; HD[x] = sz;
    }
    
    bool find(int s, int f) {
    	while (s != f) {
    		CNT[s] ++;
    		if (CNT[s] > 1) return false;
    		s = F[s];
    	}// 打标记, 祖先节点不打, 因为如果出现别的环和它共用一个节点的情况那共用节点一定是其中一个环的祖先节点
    	return true;
    }
    
    bool tarjan(int x) {
    	int v;
    	LOW[x] = DFN[x] = ++tot;
    	INSTK[x] = true; STK[++tp] = x;
    	for (int i = HD[x]; i; i = NXT[i]) {
    		v = TO[i];
    		if (!DFN[v]) {
    			F[v] = x;
    			if (!tarjan(v)) return false;
    			LOW[x] = min(LOW[x], LOW[v]);
    		}
    		else if (INSTK[v]) {
    			if (!find(x, v)) return false; //判断是否重边
    			LOW[x] = min(LOW[x], DFN[v]);
    		}
    	}
    	if (LOW[x] == DFN[x]) {
    		scc_num++;
    		if (scc_num > 1) return false; //判断强连通分量的数量
    		do {
    			v = STK[tp--];
    			INSTK[v] = false;
    		}while (v != x);
    	}
    	return true;
    }
    
    int main() {
    	scanf("%d", &T);
    	for (int i = 1; i <= T; ++i) {
    		init();
    		scanf("%d%d", &n, &m);
    		for (int j = 1, x, y; j <= m; ++j) {
    			scanf("%d%d", &x, &y);
    			add(x, y);
    		}
    		for (int j = 0; j < n; ++j)
    			if (!DFN[j] && !tarjan(j)) { ans = 0; break; }
    		if (ans) printf("YES
    ");
    		else printf("NO
    ");
    	}
    }
    
  • 相关阅读:
    semantic-ui 容器与栅格
    semantic-ui 分段
    semantic-ui 分割线
    semantic-ui 图片
    semantic-ui 标题
    semantic-ui 图标
    semantic-ui 按钮
    PHP实现无限级分类
    后端修改配置文件后,前端刷新页面--搭配鉴权
    上线新系统后,统计从旧系统切换到新系统的数据
  • 原文地址:https://www.cnblogs.com/Anding-16/p/7348129.html
Copyright © 2011-2022 走看看