zoukankan      html  css  js  c++  java
  • 割点、桥

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <string>
    #include <set>
    using namespace std;
    typedef long long ll;
    const double EPS = 1e-8;
    const int maxn = 1e2+10;
    
    struct node{
        int to, next;
    }edge[maxn*maxn*2];
    
    int cnt, head[maxn];
    
    int idx;//dfs计数 
    int dfn[maxn]; //表示dfs遍历到该节点的序号,也就是顺序值
    int low[maxn]; //表示当前顶点不通过父亲节点能访问到的祖先节点(父亲节点上面的节点)中的最小顺序值
    bool cut[maxn];//是否为割点 
    
    void addEdge(int u, int v)
    {
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        head[u] = cnt++;
    }
    //以u为根节点dfs过程中产生一棵搜索树 
    void Tarjan(int u, int pre)
    {
        dfn[u] = low[u] = ++idx;
        int son = 0;
        for(int i = head[u]; i; i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == pre) continue;
            if(!dfn[v])
            {
                son++;
                Tarjan(v, u);
                low[u] = min(low[u] , low[v]);
                //如果u不是树根,且存在儿子v使得dfn(u)<=low(v) 也就是说儿子v无法绕过父亲u到达比父亲时间戳小的点 
                if(u != pre && low[v] >= dfn[u]) cut[u] = true;
                //if(low[v] > dfn[u] ) (u,v)边是桥 
            }
            else
                low[u] = min(low[u], dfn[v]);
        }
    	//如果u是树根,并且u不止一个子树 
        if(u == pre && son > 1) cut[u] = true;
    }
    
    void init()
    {
        cnt = 1;
        memset(head, 0, sizeof(head));
        idx = 0;
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(cut, false, sizeof(cut));
    }
    
    int main()
    {
        int n;
        while(scanf("%d", &n) && n)
        {
            init();
            int u, v;
            while(scanf("%d", &u) && u)
            {
                while(getchar()!='
    ')
                {
                    scanf("%d", &v);
                    addEdge(u, v);
                    addEdge(v, u);
                }
            }
    
            Tarjan(1, 1);
            int ans = 0;
            for(int i = 1; i<=n; i++)
                if(cut[i]) ans++;
    
            printf("%d
    ", ans);
        }
    }
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <string>
    
    using namespace std;
    typedef long long ll;
    const double EPS = 1e-8;
    const int maxn = 1e2+10;
    
    int ans;
    struct node{
        int to, next;
    }edge[maxn*maxn*2];
    
    int cnt, head[maxn];
    
    int idx;//dfs计数 
    int dfn[maxn]; //表示dfs遍历到该节点的序号,也就是顺序值
    int low[maxn]; //表示当前顶点不通过父亲节点能访问到的祖先节点(父亲节点上面的节点)中的最小顺序值
    
    vector< pair<int ,int > > bridge; 
    bool cmp(pair<int ,int > a, pair<int ,int > b){
    	if(a.first == b.first) return a.second < b.second;
    	return a.first < b.first;
    }
    
    void addEdge(int u, int v)
    {
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        head[u] = cnt++;
    }
    //以u为根节点dfs过程中产生一棵搜索树 
    void Tarjan(int u, int pre)
    {
        dfn[u] = low[u] = ++idx;
        for(int i = head[u]; i; i = edge[i].next)
        {
            int v = edge[i].to;
            //if(v == pre) continue;
            if(!dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u] , low[v]);
    
                if(low[v] > dfn[u] ){ //(u,v)边是桥 
                	bridge.push_back(make_pair(min(u , v) , max(u , v)));
            	}
            } 
            else if(v != pre)
                low[u] = min(low[u], dfn[v]);
        }
    }
    
    void init(){
    	bridge.clear();
    	ans = 0;
        cnt = 1;
        memset(head, 0, sizeof(head));
        idx = 0;
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
    }
    
    int main()
    {
        int n;
        while(scanf("%d", &n) != EOF)
        {
        	if(n == 0){
        		printf("0 critical links
    ");
        		printf("
    ");
        		continue;
    		}
            init();
            int u, v, x;
            for(int i=1; i<=n ;i++){
            	scanf("%d (%d)",&u, &x);
    			for(int i=1; i<=x; i++){
    				scanf("%d",&v);
    				addEdge(u , v);
    				addEdge(v , u);
    			}
    		} 
    		for(int i=0; i<n; i++){
    			if(!dfn[i]) Tarjan(i, i);
    		}
            sort(bridge.begin(), bridge.end(), cmp);
            printf("%d critical links
    ",bridge.size());
            for(int i=0; i<bridge.size(); i++){
            	printf("%d - %d
    ",bridge[i].first, bridge[i].second);
    		}
    		printf("
    ");
        }
        return 0;
    }
    
    
  • 相关阅读:
    我的大厂面试经历(附100+面试题干货)
    大厂面试题:集群部署时的分布式 session 如何实现?
    【转载】Android数据库(SqlLite)操作和db文件查看
    【转载】android ListView详解
    C#根据经纬度获取物理地址
    C#计算两个经纬度的距离
    EXT编写日志文件
    动态数组
    System.Windows.Forms.Timer和System.Timers.Timer的区别 [转]
    SQL Prompt 3 优秀的SQL查询工具 收藏
  • 原文地址:https://www.cnblogs.com/czsharecode/p/10803186.html
Copyright © 2011-2022 走看看