zoukankan      html  css  js  c++  java
  • hdu3394--Railway(点的双连通分量)

    一个公园中有 n 个景点,景点之间通过无向的道路来连接(明显的点双

    ),如果至少两个环公用一条路,路上的游客就会发生冲突;如果一条路不属于任何的环,这条路就没必要修

    问,有多少路不必修,有多少路会发生冲突

    每一个连通块中,如果边数大于点数,这个块中所有的边全部是冲突边。

    所有桥为不需要修建的路。

    点双连通分量:对于一个连通图,如果任意两点至少存在两条“点不重复”的路径,则说这个图是点双连通的(一般简称双连通),简单来说就是任意两条边都在同一个简单环中,即内部无割顶。
    多余边:不在任何环中,一定是桥。

    冲突边:如果一个环内的边数大于点数,那么这个环内所有边都是“冲突边”。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <stack>
    using namespace std;
    typedef long long ll;
    #define cls(s,h) memset(s,h,sizeof s)
    const int maxn = 1e5 + 7;
    int n , m ;
    int tot;
    struct  edge
    {
        int to,from,nxt;
    }e[maxn << 1];
    
    int head[maxn];
    void add_edge(int u , int v ){
        e[tot].from = u ;
        e[tot].to = v;
        e[tot].nxt = head[u];
        head[u] = tot++;
    }
    
    int dfn[maxn],low[maxn],idx;
    stack<edge> stk;
    set<int> bcc;
    int cut; //brige
    int ans; //the outway brige
    int flag;
    void tanjan(int u , int pre){
        dfn[u] = low[u] = ++idx;
        for(int i = head[u]; ~i;i = e[i].nxt){
            int v = e[i].to;
            if(v == pre) continue;
            if(!dfn[v]){
                stk.push(e[i]);
                tanjan(v,u);
                low[u] = min(low[u],low[v]);
                if(low[v] >= dfn[u]){//割点
                    edge tmp;
                    int cnt = 0;
                    bcc.clear();
                    //bcc[++flag].push(e[i]);
                    do{//找v.DCC的子集
                        cnt++;//子集的边数
                        tmp = stk.top();
                        stk.pop();
                        //点数
                        bcc.insert(tmp.from);
                        bcc.insert(tmp.to);
                    }while(tmp.from != u || tmp.to != v);
                    if(cnt > bcc.size()) ans += cnt;
                   // flag ++;
                }
                if(low[v] > dfn[u]) ++cut;
            }else if(dfn[v] < dfn[u]){
                stk.push(e[i]);
                low[u] = min(low[u],dfn[v]);
            }
        }
    }
    
    void init(){
        cls(head,-1);
        cls(dfn,0);
        flag = ans = cut = tot = idx = 0;
    }
    
    int main(int argc, char const *argv[])
    {
        while(scanf("%d %d",&n,&m) && n + m){
            int u , v;
            init();
            for(int i = 1;i <= m ;i ++){
                scanf("%d %d",&u,&v);
                add_edge(u,v);
                add_edge(v,u);
            }
            for(int i = 1;i <= n;i ++){
                if(!dfn[i]) tanjan(i,-1);
            }
            printf("%d %d
    ",cut,ans );
        }
        return 0;
    }
    View Code
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <stack>
    using namespace std;
    typedef long long ll;
    #define cls(s,h) memset(s,h,sizeof s)
    const int maxn = 1e5 + 7;
    int n , m ;
    int tot;
    struct  edge
    {
        int to,from,nxt;
    }e[maxn << 1];
    
    int head[maxn];
    void add_edge(int u , int v ){
        e[tot].from = u ;
        e[tot].to = v;
        e[tot].nxt = head[u];
        head[u] = tot++;
    }
    
    int dfn[maxn],low[maxn],idx;
    stack<edge> stk;
    set<int> bcc;
    int cut; //brige 桥
    int ans; //the outway brige 冲突的边
    int flag;
    void tanjan(int u , int pre){
        dfn[u] = low[u] = ++idx;
        for(int i = head[u]; ~i;i = e[i].nxt){
            int v = e[i].to;
            if(v == pre) continue;
            if(!dfn[v]){
                stk.push(e[i]);
                tanjan(v,u);
                low[u] = min(low[u],low[v]);
                if(low[v] >= dfn[u]){//割点 割点判定法则
                    edge tmp;
                    int cnt = 0;
                    bcc.clear();
                    //bcc[++flag].push(e[i]);
                    do{//找v.DCC的子集
                        cnt++;//子集的边数
                        tmp = stk.top();
                        stk.pop();
                        //点数
                        bcc.insert(tmp.from);
                        bcc.insert(tmp.to);
                    }while(tmp.from != u || tmp.to != v);
                    if(cnt > bcc.size()) ans += cnt;
                   // flag ++;
                }
                if(low[v] > dfn[u]) ++cut;
            }else if(dfn[v] < dfn[u]){
                stk.push(e[i]);
                low[u] = min(low[u],dfn[v]);
            }
        }
    }
    
    void init(){
        cls(head,-1);
        cls(dfn,0);
        flag = ans = cut = tot = idx = 0;
    }
    
    int main(int argc, char const *argv[])
    {
        while(scanf("%d %d",&n,&m) && n + m){
            int u , v;
            init();
            for(int i = 1;i <= m ;i ++){
                scanf("%d %d",&u,&v);
                add_edge(u,v);
                add_edge(v,u);
            }
            for(int i = 1;i <= n;i ++){
                if(!dfn[i]) tanjan(i,-1);
            }
            printf("%d %d
    ",cut,ans );
        }
        return 0;
    }
    更新
  • 相关阅读:
    SpringMvc 框架
    面试:你最大的长处和弱点分别是什么?这些长处和弱点对你在企业的业绩会有什么样的影响?
    线程、并发、并行、进程是什么,以及如何开启新的线程?
    面向对象三大特性
    一台客户端有三百个客户与三百个客户端有三百个客户对服务器施压,有什么区别?
    JavaScript 引擎
    Spring Data JPA简介 Spring Data JPA特点
    博主博客
    微信相关
    关于正则表达式
  • 原文地址:https://www.cnblogs.com/DWVictor/p/11333607.html
Copyright © 2011-2022 走看看