解题报告
题目 :http://poj.org/problem?id=3352 (3177)
题目大意 :对于无向图G最少补给条边能使其变为双连通图。
思路 :利用Tarjan算法缩点后,找到度数为1 的点个数ans,则答案是(ans+1)/2.
Dfn[i] :i点的时间戳。
Low[v] : 讲过非父子边所能到达的最早的点。
对于一条边(u,v)如果我们发现dfn[u] < low[v]时。说明从V不经过父子边是无法走到u前面的点的,也就是说(u,v)是一条割边。
提交情况 N次wa后AC
AC code:
#include <stdio.h>
#include <string.h>
#define MAXN 5100
#define MAXE 11000
#define MIN(a, b) ((a) < (b) ? (a) : (b))
struct EDGE{
int to, next;
};
EDGE edges[MAXE];
inthead[MAXN], dfn[MAXN], low[MAXN], colour[MAXN], ad, times;
voidclear(){
ad = 0;
memset(head, -1, sizeof(head));
}
void insert(int x,int y){
edges[ad].to = y; edges[ad].next = head[x]; head[x] = ad ++;
}
void dfs(int u, int father){
int p;
dfn[u] = low[u] = ++times;
for(p = head[u]; ~p; p = edges[p].next){
if(edges[p].to != father){
if(dfn[edges[p].to]) low[u] = MIN(low[u], dfn[edges[p].to]);
else{
dfs(edges[p].to, u);
low[u] = MIN(low[u], low[edges[p].to]);
if(dfn[u] < low[edges[p].to]) colour[p] = colour[p ^ 1] = 1;
}
}
}
}
void Tarjan(int n){
int i;
times = 0;
memset(dfn, 0, sizeof(dfn));
memset(colour, 0, sizeof(colour));
for(i = 1; i <= n; i ++)
if(!dfn[i]) dfs(i, -1);
}
void find(int u, int mark){
int i;
low[u] = mark;
for(i = head[u]; ~i; i = edges[i].next)
if(!colour[i] && !low[edges[i].to]) find(edges[i].to, mark);
}
voidGet_ans(int n){
int i, p, point = 0;
memset(low, 0, sizeof(low));
for(i = 1; i <= n; i ++){
if(!low[i]) find(i, ++point);
}
memset(dfn, 0, sizeof(dfn));
for(i = 1; i <= n; i ++)
for(p = head[i]; ~p; p = edges[p].next)
if(low[i] != low[edges[p].to]) dfn[low[i]] ++;
int ans = 0;
for(i = 1; i <= point; i ++)
if(dfn[i] == 1) ans ++;
printf("%d\n", (ans + 1) / 2);
}
int main(){
int F, R, i, x, y;
while(~scanf("%d %d", &F, &R)){
clear();
for(i = 0; i < R; i ++){
scanf("%d %d", &x, &y);
insert(x, y);
insert(y, x);
}
Tarjan(F);
Get_ans(F);
}
return 0;
}