您的位置:首页 > 其它

POJ 3177 Redundant Paths 边双连通分支

2015-05-20 17:13 375 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: