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;
    }
    更新
  • 相关阅读:
    Knockout应用开发指南 第八章:简单应用举例(2)
    微软ASP.NET站点部署指南(7):生产环境部署
    Knockout应用开发指南 第七章:Mapping插件
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(6)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(5)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(3)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(9)
    《Microsoft Sql server 2008 Internals》读书笔记第九章Plan Caching and Recompilation(8)
    Microsoft Visual Studio .NET 2003 引导程序插件下载地址(非官方)
    Vs2010在没有安装SQL Server 2005/2008 Express时如何连接MDF数据文件?
  • 原文地址:https://www.cnblogs.com/DWVictor/p/11333607.html
Copyright © 2011-2022 走看看