HDU 3394 Railway 【点双联通】

传送门
// 有一个公园有n个景点,公园的管理员准备修建m条道路,并且安排一些形成回路的参观路线。如果一条道路被多条道路公用,那么这条路是冲突的;如果一条道路没在任何一个回路内,那么这条路是不冲突的

问分别有多少条有冲突的路和没有冲突的路

思路: 如果某条边有冲突, 那么它至少存在于两个环中, 也就是我们要判断图中的环, 其边于点的关系:
边数 = 点数 : 一个环
边数 > 点数 : >一个环
边数 < 点数 : 一个线段, 即桥. 也就是不冲突的路

AC Code

const int maxn = 1e4 + 5;
int cas=1;
int dfn[maxn], low[maxn], cut[maxn];
int n, m;
int cnt, head[maxn];
int dfs_id, cut_num;
int vis[maxn];
stack<int >st;
struct node
{
    int from, to, next;
}e[maxn*20];

void add(int u, int v)
{
    e[cnt] = node{u, v, head[u]};
    head[u] = cnt++;
}
int ans1, ans2;
void init()
{
    Fill(dfn, 0); Fill(low, 0); Fill(cut, 0);
    cnt = 0; Fill(head, -1);
    dfs_id = cut_num = 0;
    ans1 = ans2 = 0;
}
void tarjan(int u,int fa)
{
    int son = 0;
    dfn[u] = low[u] = ++dfs_id;
    for(int i = head[u] ; ~i ; i = e[i].next) {
        int v = e[i].to;
        if(v == fa) continue;
        if(!dfn[v]){
            son++;
            st.push(i);  //把边的编号推进去.
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]){
                cut[u] = 1; Fill(vis, 0);
                int c1 = 0, c2 = 0;
                while (1) {
                    int id = st.top(); st.pop();
                    if (!vis[e[id].from]) c1++;
                    if (!vis[e[id].to]) c1++;
                    vis[e[id].from] = vis[e[id].to] = 1;
                    c2++;
                    if (e[id].from == u && e[id].to == v) {
                        if (c1 > c2) ans1++;
                        if (c1 < c2) ans2 += c2;
                        break;
                    }
                }
            }
        }
        else if(dfn[v] < dfn[u]){
            st.push(i);
            low[u] = min(low[u],dfn[v]);
        }
    }
    if (fa == -1 && son > 1) cut[u] = 1;
}

void solve()
{
    while(~scanf("%d%d", &n, &m)){
        if (n + m == 0) break;
        init();
        for (int i = 1 ; i <= m ; i ++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v); add(v, u);
        }
        for(int i = 1 ; i <= n ; i ++) {
            if(!dfn[i]) tarjan(i, -1);
        }
        printf("%d %d\n", ans1, ans2);
    }
}

你可能感兴趣的:(强联通_点边双联通_桥割点)