【UVa】11374 Airport Express 最短路

题型:枚举+最短路


题目大意:

给你一个无向图,n个点,m条普通边,k条特殊边,s为起点,t为终点。

定义(u,v,w)为一条连接u,v,花费为w的边。

现在你需要从u走到v,途中最多只能经过一次特殊边的路径,转特殊边的起点(没有输出Ticket Not Used),以及最小花费。


题目分析:

设d[0][i]为以s为起点到i的最小花费,d[1][i]为以t为起点到i的最小花费。

首先用普通边构造出图G,最短路求出G中以s到所有点的最短路以及t到所有点的最短路,然后枚举每一条特殊边(u,v,w),则ans = min{d[0][u] + d[1][v] + w}。

然后路径就在求最短路的时候顺便求一下就好了。

PS:本题出于作者习惯,Dij一律为附带手敲优先队列版本吐舌头


代码如下:


#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;

#define clear( A , X ) memset ( A , X , sizeof A )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FF( i , a , b ) for ( int i = a ; i <= b ; ++ i )

const int maxN = 505 ;
const int maxQ = 20005 ;
const int maxH = 1000005 ;
const int maxE = 1000005 ;
const int oo = 0x3f3f3f3f ;

struct Heap {
	int num , d ;
	Heap () {}
	Heap ( int D , int Num ) : d(D) , num(Num) {}
} ;

struct Edge {
	int v , n , w ;
	Edge () {}
	Edge ( int V , int W , int N ) : v(V) , w(W) , n(N) {}
} ;

struct Priority_Queue {
	Heap heap[maxH] ;
	int top ;
	
	void swap ( Heap &a , Heap &b ) {
		Heap tmp = a ; a = b ; b = tmp ;
	}
	
	int cmp ( const Heap a , const Heap b ) {
		return a.d < b.d ;
	}
	
	void Clear () {
		top = 0 ;
	}
	
	int Empty () {
		return 0 == top ;
	}
	
	void Push ( int d , int num ) {
		heap[top] = Heap ( d , num ) ;
		int o = top ++ , p = ( o - 1 ) >> 1 ;
		while ( o && cmp ( heap[o] , heap[p] ) ) {
			swap ( heap[o] , heap[p] ) ;
			o = p , p = ( o - 1 ) >> 1 ;
		}
	}
	
	int Front () {
		return heap[0].num ;
	}
	
	void Pop () {
		heap[0] = heap[-- top] ;
		int o = 0 , p = o , l = o * 2 + 1 , r = o * 2 + 2 ;
		while ( 1 ) {
			if ( l < top && cmp ( heap[l] , heap[p] ) ) p = l ;
			if ( r < top && cmp ( heap[r] , heap[p] ) ) p = r ;
			if ( p == o ) break ;
			swap ( heap[o] , heap[p] ) ;
			o = p , l = o * 2 + 1 , r = o * 2 + 2 ;
		}
	}
} ;

struct Dij {
	Priority_Queue Q ;
	Edge edge[maxE] ;
	int adj[maxN] , cntE ;
	int done[maxN] ;
	int d[2][maxN] ;
	int p[2][maxN] ;
	
	void Addedge ( int u , int v , int w ) {
		edge[cntE] = Edge ( v , w , adj[u] ) ;
		adj[u] = cntE ++ ;
		edge[cntE] = Edge ( u , w , adj[v] ) ;
		adj[v] = cntE ++ ;
	}
	
	void Init () {
		cntE = 0 ;
		Q.Clear () ;
		clear ( d , oo ) ;
		clear ( p , -1 ) ;
		clear ( adj , -1 ) ;
	}
	
	void Dijkstra ( int s , int t , int dis[] , int pre[] ) {
		clear ( done , 0 ) ;
		dis[s] = 0 ;
		Q.Push ( dis[s] , s ) ;
		while ( !Q.Empty () ) {
			int u = Q.Front () ;
			Q.Pop () ;
			if ( done[u] ) continue ;
			done[u] = 1 ;
			for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
				int v = edge[i].v ;
				if ( dis[v] > dis[u] + edge[i].w ) {
					pre[v] = u ;
					dis[v] = dis[u] + edge[i].w ;
					Q.Push ( dis[v] , v ) ;
				}
			}
		}
	}
	
	void Print1 ( int t , int i , int pre[] ) {
		if ( ~pre[i] ) Print1 ( t , pre[i] , pre ) ;
		printf ( "%d%c" , i , ( i != t ) ? ' ' : '\n' ) ;
	}
	void Print2 ( int i , int pre[] ) {
		if ( ~pre[i] ) Print2 ( pre[i] , pre ) ;
		printf ( "%d " , i ) ;
	}
	void Print3 ( int i , int pre[] ) {
		printf ( "%d%c" , i , ( ~pre[i] ) ? ' ' : '\n' ) ;
		if ( ~pre[i] ) Print3 ( pre[i] , pre ) ;
	}
} ;

Dij D ;

void work () {
	int n , m , k ;
	int u , v , w ;
	int s , t ;
	int idu , idv ;
	int cas = 0 ;
	while ( ~scanf ( "%d%d%d" , &n , &s , &t ) ) {
		if ( cas ++ )
			printf ( "\n" ) ;
		D.Init () ;
		scanf ( "%d" , &m ) ;
		REP ( i , m ) {
			scanf ( "%d%d%d" , &u , &v , &w ) ;
			D.Addedge ( u , v , w ) ;
		}
		D.Dijkstra ( s , t , D.d[0] , D.p[0] ) ;
		D.Dijkstra ( t , s , D.d[1] , D.p[1] ) ;
		int ans = D.d[0][t] ;
		int flag = 0 ;
		scanf ( "%d" , &k ) ;
		REP ( i , k ) {
			scanf ( "%d%d%d" , &u , &v , &w ) ;
			if ( ans > D.d[0][u] + D.d[1][v] + w ) {
				ans = D.d[0][u] + D.d[1][v] + w ;
				idu = u , idv = v ;
				flag = 1 ;
			}
			if ( ans > D.d[1][u] + D.d[0][v] + w ) {
				ans = D.d[1][u] + D.d[0][v] + w ;
				idu = v , idv = u ;
				flag = 1 ;
			}
		}
		//printf ( "%d %d\n" , D.d[0][5] , D.d[1][6] ) ;
		if ( !flag ) {
			D.Print1 ( t , t , D.p[0] ) ;//s->t
			printf ( "Ticket Not Used\n" ) ;
			printf ( "%d\n" , ans ) ;
		}
		else {
			D.Print2 ( idu , D.p[0] ) ;//s->idu
			D.Print3 ( idv , D.p[1] ) ;//idv->t
			printf ( "%d\n" , idu ) ;
			printf ( "%d\n" , ans ) ;
		}
	}
}

int main () {
	work () ;
	return 0 ;
}


你可能感兴趣的:(最短路,uva)