HDU Intelligence System(tarjan+缩点)

http://acm.hdu.edu.cn/showproblem.php?pid=3072

最近为了CF上的一道题,又把强连通分支的tarjan算法看了一遍,为了加深印象,就做了HDU上的这题。。。。

题意:有一个情报系统,要从0开始传播一个情报,如果两个人可以互达那么两人之间的传播费用为0 ,否则两人之间的传播费用为ci,求要情报传达到每个人的最小费用。

思路:既然一个强连通分支内的传播费用为0,求图中有几个强连通分支,缩点后求各点之间的最小费用。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#define  N 100005
#define  M 50005
using namespace std ;

const int INF = ( 1 << 30 );

struct node
{
    int e , len ;
    int next ;
}p[N] ;

int head[M] , n , m , num , cnt , id ;
bool used[M] , vist[M] ;//used[i]表示点i是否遍历过,vist[i]表示点i是否在栈里;
int dis[M] , dfn[M] , low[M] , belong[M] ;
stack<int>q ;

//初始化
void init()
{
    num = cnt = id = 0 ;
    for ( int i = 0 ; i <= n ; i++ )
    {
        dfn[i] = low[i] = 0 ;
        used[i] = vist[i] = false ;
        dis[i] = INF ;
        head[i] = -1 ;
    }
    while ( !q.empty()) q.top();
}

void add ( int x , int y , int z )
{
    p[num].e = y ;
    p[num].len = z ;
    p[num].next = head[x];
    head[x] = num++ ;
}

void tarjan( int x )
{
    int i , v ;
    dfn[x] = low[x] = ++id ;
    used[x] = vist[x] = true ;
    q.push( x ) ;
    for ( i = head[x] ; i != -1 ; i = p[i].next )
    {
        v = p[i].e ;
        if( !used[v] )
        {
            tarjan( v ) ;
            low[x] = min( low[x] , low[v] );
        }
        else if( vist[v] )
        {
            low[x] = min( low[x] , dfn[v] );
        }
    }

    if ( dfn[x] == low[x] )
    {
        cnt++ ;
        do
        {
            v = q.top();
            q.pop();
            belong[v] = cnt ;
            vist[v] = false ;
        }while( v != x ) ;
    }
}

int main()
{
    int i , j , x , y , z ;

    while ( scanf ( "%d%d" , &n , &m ) != EOF )
    {
        init();
        for ( i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d%d%d" , &x , &y , &z );
            //x++ ; y++ ;
            add ( ++x , ++y , z ) ;
        }

        for ( i = 1 ; i <= n ; i++ )
        if ( !dfn[i] )
        tarjan( i ) ;

        for ( i = 1 ; i <= n ; i++ )
        {
            for ( j = head[i] ; j != -1 ; j = p[j].next )
            {
                z = p[j].e ;
                x = belong[i]; y = belong[z] ;
                if ( x != y )
                dis[y] = min( dis[y] , p[j].len ) ;
            }
        }

        int sum = 0 ;
        for ( i = 1 ; i <= n ; i++ )
        if ( dis[i] < INF )
        sum += dis[i] ;

        printf ( "%d\n" , sum ) ;
    }
    return 0 ;
}

转载于:https://www.cnblogs.com/misty1/archive/2012/11/03/2752327.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值