poj3352,3177

解题报告

题目 http://poj.org/problem?id=3352  3177

题目大意 :对于无向图G最少补给条边能使其变为双连通图。

思路 :利用Tarjan算法缩点后,找到度数为1 的点个数ans,则答案是(ans+1/2.

Dfn[i] i点的时间戳。

Low[v] : 讲过非父子边所能到达的最早的点。

对于一条边(uv)如果我们发现dfn[u] < low[v]时。说明从V不经过父子边是无法走到u前面的点的,也就是说(uv)是一条割边。

提交情况 NwaAC

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;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值