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 ; }