zoukankan      html  css  js  c++  java
  • 【POJ 2186】Popular Cows

    http://poj.org/problem?id=2186
    tarjan求强连通分量。
    因为SD省选用WinXP+Cena评测而且不开栈,所以dfs只好写手动栈了。
    写手动栈时思路清晰一点应该是不会出错的吧。。。
    这里tarjan要开两个栈,一个是tarjan用来记录强连通分量的栈,另一个是记录dfs路径的栈。
    cur记录当前弧,fa记录dfs树上的father。
    对于扫到一个环不需要dfs下去的情况就直接处理,对于需要dfs下去的情况就把下一个点压入栈,记录这下一个点的fa为当前点,同时当前点的cur向下一个位置跳一下。
    dfs时经常需要当前点dfs所有它的dfs树上的孩子然后统计它的孩子的信息,如果写手动栈记录哪个后继节点被dfs了需要统计信息和哪个后继节点没有被dfs(这只是图上的情况,树上显然所有后继节点都必须被dfs)不需要统计信息就非常麻烦了。
    有一个比较巧的做法是记录上述的fa,如果一个点的当前弧都跳完了,说明这个点的信息都处理好了,然后把这个点的信息传到它的fa上,它的fa就不需要记录哪个后继节点需要统计信息哪个后继节点不需要统计信息了。

    #include<cstdio>
    #include<bitset>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 10003;
    const int M = 50003;
    
    bitset <N> inst;
    struct node {int nxt, to;} E[M];
    int dfn[N], low[N], tot = 0, fa[N], bel[N], sta[N], statop = 0, st[N], top, cnt = 0, point[N], cur[N], n, m;
    
    void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}
    
    void tarjan(int x) {
    	st[top = 1] = x;
    	while (top) {
    		int u = st[top];
    		if (!dfn[u]) {
    			inst[u] = 1; sta[++statop] = u;
    			low[u] = dfn[u] = ++cnt;
    		}
    		if (cur[u]) {
    			int v = E[cur[u]].to;
    			if (inst[v]) low[u] = min(low[u], dfn[v]);
    			else if (!dfn[v]) fa[st[++top] = v] = u;
    			cur[u] = E[cur[u]].nxt;
    		} else {
    			low[fa[u]] = min(low[fa[u]], low[u]);
    			if (low[u] == dfn[u]) {
    				++tot;
    				while (sta[statop] != u) {
    					bel[sta[statop]] = tot;
    					inst[sta[statop]] = 0;
    					--statop;
    				}
    				inst[u] = 0;
    				bel[u] = tot; --statop;
    			}
    			--top;
    		}
    	}
    }
    
    int du[N];
    
    int main() {
    	int u, v;
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d", &u, &v);
    		ins(u, v);
    	}
    	for (int i = 1; i <= n; ++i)
    		cur[i] = point[i];
    	
    	cnt = 0;
    	for (int i = 1; i <= n; ++i)
    		if (!dfn[i]) tarjan(i);
    	
    	for (int i = 1; i <= n; ++i)
    		for (int j = point[i]; j; j = E[j].nxt)
    			if (bel[i] != bel[E[j].to])
    				++du[bel[i]];
    	
    	int mark = 0;
    	for (int i = 1; i <= tot; ++i)
    		if (du[i] == 0)
    			if (mark == 0)
    				mark = i;
    			else
    				{puts("0"); return 0;}
    	
    	int ret = 0;
    	for (int i = 1; i <= n; ++i)
    		if (bel[i] == mark)
    			++ret;
    	printf("%d
    ", ret);
    	return 0;
    }
    
  • 相关阅读:
    洛谷P1071 潜伏者
    2019BJFU 网站设计(孙俏-web前端开发)实验代码-181002222
    反思——P1307 数字反转
    洛谷P1067 多项式输出
    湖南大学第十五届程序设计竞赛(重现赛)
    2019河北省大学生程序设计竞赛(重现赛)
    2019BJFU C++实验习题(完结)
    配置android source 在ubuntu中编译环境
    Android屏幕保持唤醒状态
    Android richtext
  • 原文地址:https://www.cnblogs.com/abclzr/p/6639707.html
Copyright © 2011-2022 走看看