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\n",cut,ans );
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/DWVictor/p/11333607.html