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;
}

原文地址:https://www.cnblogs.com/KirinSB/p/9781332.html

时间: 2024-11-07 08:32:12

poj3352 Road Construction & poj3177 Redundant Paths (边双连通分量)题解的相关文章

poj3177 Redundant Paths 边双连通分量

#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define eps 1e-

[POJ3177]Redundant Paths(双连通图,割边,桥,重边)

题目链接:http://poj.org/problem?id=3177 和上一题一样,只是有重边. 如何解决重边的问题? 1.  构造图G时把重边也考虑进来,然后在划分边双连通分量时先把桥删去,再划分,其中桥的一端的割点归入当前正在划分的边双连通分量.这个处理比较麻烦: 2.  在输入图G的边时,若出现重边,则不把重边放入图G,然后在划分边双连通分量时依然用Low划分. 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓

Road Construction POJ - 3352 (边双连通分量)

Road Construction POJ - 3352 题意:一个无向图(无重边),问至少还要加多少边使得去掉任意一条边后任意两点仍可互达. 无向图的边双连通分量(无重边) 先用一次dfs标记出割边,然后dfs标记出各联通分量 再根据割边,缩点重新建图,生成一颗树 则答案就是(叶子树+1)/2. 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring

POJ 3177 Redundant Paths 边双连通分量+缩点

题目链接: poj3177 题意: 给出一张连通图,为了让任意两点都有两条通路(不能重边,可以重点),至少需要加多少条边 题解思路: 分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点. 缩点后,新图是一棵树,树的边就是原无向图桥. 现在问题转化为:在树中至少添加多少条边能使图变为双连通图. 结论:添加边数=(树中度为1的节点数+1)/2 具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上

【POJ 3177】Redundant Paths(双连通分量)

求出每个双连通分量缩点后的度,度为1的点即叶子节点.原图加上(leaf+1)/2条边即可变成双连通图. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <map> using namespace std; const int N = 5010; const int M = 10010; struct Edge { int

POJ 3352 Road Construction 使得无向图边变双连通图

点击打开链接 Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8168   Accepted: 4106 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of

【连通图|边双连通+缩点】POJ-3352 Road Construction

Road Construction Time Limit: 2000MS Memory Limit: 65536K Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the roads on the tropical island paradise of Remo

POJ3177 Redundant Paths 双连通分量

Redundant Paths Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of

【连通图|边双连通+缩点】POJ-3177 Redundant Paths

Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K       Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the T