poj1236 强联通分量(tarjan)

本文介绍了一道图论问题的解题思路,利用Tarjan算法求解有向图的强连通分量,进而计算最少出发点数及使图强联通所需的最少边数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题报告

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

题目大意 :给定一个有向图,求下面两个量:

1 :最少从几个点出发能遍历全图。

2 :最少加几条边能使原图强联通。

算法 tarjan求强联通分量

思路 :“最少从几个点出发能遍历全图”的点数是将原图缩点后入度为零的点的个数。

           “最少加几条边能使原图强联通”的边数是将原图缩点后出度为零的点和入读为零的点中的最大值。

:当只有一个缩点时,边数为0.

提交情况 wrong answer 2 (边数求成了出度为零的点的个数。。)

                Accepted 1

//poj2553也是类似题

AC code

#include <stdio.h>

#include <string.h>

 

#define MAXN 2000

#define MAXM (MAXN * MAXN)

 

struct NODE{

    int to, next;

};

NODE edges[MAXM];

inthead[MAXN], ad;

 

intdfn[MAXN], low[MAXN], vis[MAXN], strack[MAXN], belong[MAXN], in[MAXN], out_degree[MAXN], in_degree[MAXN];

int times, tarjan_total, top;

 

void dfs(int u){

    int p;

    low[u] = dfn[u] = times ++;

    strack[++top] = u;

    vis[u] = 1;

    in[u] = 1;

    for(p = head[u];  ~p; p = edges[p].next){

       if(!vis[edges[p].to]){

           dfs(edges[p].to);

           if(low[u] > low[edges[p].to])

              low[u] = low[edges[p].to];

       }

       else

           if(in[edges[p].to] && low[u] > low[edges[p].to]) low[u] = low[edges[p].to];

    }

    if(dfn[u] == low[u]){

       tarjan_total ++;

       belong[u] = tarjan_total;

       in[u] = 0;

       while((p = strack[top--]) != u){

           low[p] = low[u];

           belong[p] = tarjan_total;

           in[p] = 0;

       }

    }

}

 

void tarjan(int n){

    int i;

    times = 0;

    tarjan_total = 0;

    top = -1;

    memset(vis, 0 ,sizeof(vis));

    memset(in, 0, sizeof(in));

    for(i = 1; i <= n; i ++)

       if(!vis[i]) dfs(i);

}

 

void Getans(int n){

    int i, j;

    memset(in_degree, 0, sizeof(in_degree));

    memset(out_degree, 0, sizeof(out_degree));

    for(i = 1; i <= n; i ++)

       for(j = head[i]; ~j; j = edges[j].next){

           if(belong[i] != belong[edges[j].to]){

              out_degree[belong[i]] ++;

              in_degree[belong[edges[j].to]] ++;

           }

       }

    int ans1 = 0, ans2 = 0;

    for(i = 1; i <= tarjan_total; i ++){

       if(in_degree[i] == 0) ans1 ++;

       if(out_degree[i] == 0) ans2 ++;

    }

    if(tarjan_total == 1) ans2 = 0;

    else ans2 = ans1 > ans2 ? ans1 : ans2;

    printf("%d\n%d\n", ans1, ans2);

}

 

int main(){

    int n, t, i;

    while(~scanf("%d", &n)){

       ad = 0;

       memset(head, -1, sizeof(head));

       for(i = 1; i <= n; i ++)

           while(~scanf("%d", &t), t){

              edges[ad].to = t; edges[ad].next = head[i]; head[i] = ad ++;

           }

       tarjan(n);

       Getans(n);

    }

    return 0;

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值