poj3352 Road Construction & poj3177 Redundant Paths (边双连通分量)题解

题意:有n个点,m条路,问你最少加几条边,让整个图变成边双连通分量。

思路:缩点后变成一颗树,最少加边 = (度为1的点 + 1)/ 2。3177有重边,如果出现重边,用并查集合并两个端点所在的缩点后的点。

代码:

/*3352*/
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 5000 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
struct Edge{
    int u, v, next;
}edge[maxn << 1];
int index, scc_cnt, tot;    //scc_cnt记录SCC
int dfn[maxn], low[maxn], sccno[maxn], in[maxn], head[maxn];
stack<int> s;
void addEdge(int u, int v){
    edge[tot].v = v;
    edge[tot].u = u;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void tarjan(int u, int pre){
    dfn[u] = low[u] = ++index;
    s.push(u);
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].v;
        if(!dfn[v]){
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(v != pre){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        scc_cnt++;
        int a;
        while(1){
            a=s.top();
            s.pop();
            sccno[a] = scc_cnt;
            if(a == u) break;
        }
    }
}

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    index = scc_cnt = tot = 0;
    while(!s.empty()) s.pop();
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    for(int i = 0; i < m; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            tarjan(i, 0);
    }
    memset(in, 0, sizeof(in));
    for(int i = 0; i < tot; i += 2){
        int u = edge[i].u, v = edge[i].v;
        if(sccno[u] != sccno[v]){
            in[sccno[u]]++;
            in[sccno[v]]++;
        }
    }
    int cnt = 0;
    for(int i = 1; i <= scc_cnt; i++){
        if(in[i] == 1) cnt++;
    }
    printf("%d\n", (cnt + 1) / 2);
    return 0;
}
/*3177*/
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 5000 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
struct Edge{
    int u, v, next;
}edge[maxn << 1];
int index, scc_cnt, tot;    //scc_cnt记录SCC
int dfn[maxn], low[maxn], sccno[maxn], in[maxn], head[maxn];
stack<int> s;
map<int, int> mp[maxn];
int Find(int x){
    return sccno[x] == x? x : sccno[x] = Find(sccno[x]);
}
void addEdge(int u, int v){
    edge[tot].v = v;
    edge[tot].u = u;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void tarjan(int u, int pre){
    dfn[u] = low[u] = ++index;
    s.push(u);
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].v;
        if(!dfn[v]){
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(v != pre){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        scc_cnt++;
        int a;
        while(1){
            a=s.top();
            s.pop();
            sccno[a] = u;
            if(a == u) break;
        }
    }
}

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    index = scc_cnt = tot = 0;
    while(!s.empty()) s.pop();
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    for(int i = 0; i < m; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            tarjan(i, 0);
    }
    for(int i = 1; i <= n; i++) mp[i].clear();
    memset(in, 0, sizeof(in));
    for(int i = 0; i < tot; i += 2){
        int u = edge[i].u, v = edge[i].v;
        if(u > v) swap(u, v);
        mp[u][v]++;
        if(mp[u][v] == 2){
            int fx = Find(u), fy = Find(v);
            if(fx != fy){
                sccno[fx] = fy;
            }
        }
    }
    for(int i = 0; i < tot; i += 2){
        int u = edge[i].u, v = edge[i].v;
        int fx = Find(u), fy = Find(v);
        if(fx != fy){
            in[fx]++;
            in[fy]++;
        }
    }
    int cnt = 0;
    for(int i = 1; i <= n; i++){
        if(sccno[i] == i && in[i] == 1) cnt++;
    }
    printf("%d\n", (cnt + 1) / 2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/KirinSB/p/9781332.html
今日推荐