标签:
题目链接:http://poj.org/problem?id=3177
题目大意是 给一个无向图,求至少要添加多少条边才能使其变为边双连通图
边双连通图简单来说就是联通且没有割边(桥)
图是连通的,并且没有给重边(所以程序中没有处理重边)
思想是缩环,然后统计有多少个叶子节点,答案为(叶子节点数目+1)/ 2
统计叶子的过程是先找出所有的割边
然后逐个遍历点,遍历边,若边是割边则去点所在的scc的度数加一
这样到最后度数为1的scc就是叶子
完全参考自kuangbin模板
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> #include <ctime> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> P; template<class T> inline bool read(T &n) { T x = 0, tmp = 1; char c = getchar(); while((c < ‘0‘ || c > ‘9‘) && c != ‘-‘ && c != EOF) c = getchar(); if(c == EOF) return false; if(c == ‘-‘) c = getchar(), tmp = -1; while(c >= ‘0‘ && c <= ‘9‘) x *= 10, x += (c - ‘0‘),c = getchar(); n = x*tmp; return true; } template <class T> inline void write(T n) { if(n < 0) { putchar(‘-‘); n = -n; } int len = 0,data[20]; while(n) { data[len++] = n%10; n /= 10; } if(!len) data[len++] = 0; while(len--) putchar(data[len]+48); } //----------------------------------- const int maxn = 5010; const int maxm = 20010; struct Edge { int to, next; bool cut; }edge[maxm]; int head[maxn], tot; int Low[maxn], DFN[maxn], Stack[maxn], Belong[maxn]; int Index, top; int scc; int bridge; bool Instack[maxn]; int num[maxn]; void addedge(int u, int v) { edge[tot].to = v; edge[tot].next = head[u]; edge[tot].cut = false; head[u] = tot++; edge[tot].to = u; edge[tot].next = head[v]; edge[tot].cut = false; head[v] = tot++; } void Tarjan(int u, int pre) { int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(v == pre) continue; if(!DFN[v]) { Tarjan(v, u); if(Low[u] > Low[v]) Low[u] = Low[v]; if(Low[v] > DFN[u]) { bridge++; edge[i].cut = true; edge[i^1].cut = true; } } else if(Instack[v] && Low[u] > Low[v]) Low[u] = Low[v]; } if(Low[u] == DFN[u]) { scc++; do { v = Stack[--top]; Instack[v] = false; Belong[v] = scc; num[scc]++; } while(v != u); } } int du[maxn]; void solve(int N) { memset(DFN, 0, sizeof(DFN)); memset(Instack, 0, sizeof(Instack)); memset(num, 0, sizeof(num)); Index = scc = top = 0; for(int i = 1; i <= N; i++) { if(!DFN[i]) Tarjan(i, 0); } for(int i = 1; i <= N; i++) { for(int j = head[i]; j != -1; j = edge[j].next) { if(edge[j].cut) //若为桥,则去点所在的scc的度+1 du[Belong[edge[j].to]]++; } } int leaf = 0; for(int i = 1; i <= scc; i++) //找“叶子” 即度为1的节点 { if(du[i] == 1) leaf++; } printf("%d\n", (leaf + 1)/ 2); } void init() { tot = 0; bridge = 0; memset(head, -1, sizeof(head)); } int main() { //freopen("in.txt", "r", stdin); int F, R; scanf("%d%d", &F, &R); init(); for(int i = 0; i < R; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); } solve(F); return 0; }
POJ 3177 Redundant Paths 边双连通分支
标签:
原文地址:http://www.cnblogs.com/dishu/p/4517670.html