poj 3114 Countries in War(tarjan + spfa)

http://poj.org/problem?id=3114

题意:给出N个城市和M条路,每封信可以从城市A到城市B花费时间ci,但路是单向的,如果两个城市可以互达,则这两个城市属于同一个国家,而一封信在同一个国家间传递不花费时间,然后给出K组查询,问从X到Y所花的最小时间。

解题过程:这题和poj上的3592一样,先求出图中的强连通分支,缩点后去最短路,用的spfa求最短路,discuss里有人说floyd会超时,所以直接用了spfa,但是开始的时候数组开小了,找了好久才找出来。

代码:

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

const int INF = ( 1 << 30 ) ;

struct node
{
    int e , val ;
    int next ;
}p[M] , q[M] ;

int headp[N] , headq[N] , dfn[N] , low[N] , dis[N] , belong[N] ;
bool vist[N] , used[N] ;
int n , m , cnt , id , nump , numq ;
queue<int>qx ;
stack<int>st ;

void addp ( int x , int y , int z )
{
    p[nump].e = y ;
    p[nump].val = z ;
    p[nump].next = headp[x] ;
    headp[x] = nump++ ;
}

void addq ( int x , int y , int z )
{
    q[numq].e = y ;
    q[numq].val = z ;
    q[numq].next = headq[x] ;
    headq[x] = numq++ ;
}

void init()
{
    nump = numq = 0 ;
    cnt = id = 0 ;
    memset( headp , -1 , sizeof ( headp )) ;
    memset( headq , -1 , sizeof ( headq )) ;
    memset( dfn , 0 , sizeof ( dfn )) ;
    memset( low , 0 , sizeof ( low )) ;
    memset( belong , 0 , sizeof ( belong )) ;
    for (int i = 1 ; i <= n ; i++ )
    {
        //dis[i] = INF ;
        vist[i] = used[i] = false ;
    }
    while ( !st.empty()) st.pop();
}

void tarjan( int x )
{
    int u , v ;
    dfn[x] = low[x] = ++id ;
    used[x] = vist[x] = true ;
    st.push( x ) ;

    for ( int i = headp[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
        {
            u = st.top();
            st.pop();
            belong[u] = cnt ;
            vist[u] = false ;
        }while ( u != x ) ;
    }
}

void Spfa( int s )
{
    int u , v ;
    while ( !qx.empty()) qx.pop();
    for ( u = 0 ; u <= n ; u++ )
    {
        dis[u] = INF ;
        vist[u] = false ;
    }
    dis[s] = 0 ;
    vist[s] = true ;
    qx.push( s ) ;

    while ( !qx.empty())
    {
        u = qx.front();
        qx.pop();
        vist[u] = false ;

        for ( int i = headq[u] ; i != -1 ; i = q[i].next )
        {
            v = q[i].e ;
            if ( dis[v] > dis[u] + q[i].val )
            {
                dis[v] = dis[u] + q[i].val ;
                if ( !vist[v] )
                {
                    vist[v] = true ;
                    qx.push( v ) ;
                }
            }
        }
    }
}

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

    //freopen( "input.txt" , "r" , stdin ) ;
    while ( scanf ( "%d%d" , &n , &m ) , n + m )
    {
        //初始化
        init();
        for ( i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d%d%d" , &x , &y , &z ) ;
            addp ( x , y , z ) ;
        }
        
        //求强连通分支
        for ( i = 1 ; i <= n ; i++ )
        if ( !dfn[i] )
        tarjan( i );
        
        //缩点后建图
        for ( i = 1 ; i <= n ; i++ )
        {
            for ( j = headp[i] ; j != -1 ; j = p[j].next )
            {
                x = p[j].e ;
                if ( belong[i] != belong[x] )
                {
                    addq ( belong[i] , belong[x] , p[j].val ) ;
                }
            }
        }
        /*for ( i = 1 ; i <= n ; i++ )
        {
            cout<<i<<":"<<belong[i]<<endl ;
        }*/
        //cout<<numq<<endl;
        
        //查询
        scanf ( "%d" , &k ) ;
        while ( k-- )
        {
            scanf ( "%d%d" , &x , &y ) ;
            if ( belong[x] == belong[y] && belong[x] != 0 )
            {
                printf ( "0\n" );
                continue ;
            }
            x = belong[x] ;
            y = belong[y] ;
            Spfa( x ) ;
            if ( dis[y] == dis[0] )
            {
                printf ( "Nao e possivel entregar a carta\n" );
            }
            else
            {
                printf ( "%d\n" , dis[y] ) ;
            }
        }
        printf ( "\n" );
    }
    return 0 ;
}

 

原文地址:https://www.cnblogs.com/misty1/p/2754115.html