传送门:【HDU】4725 The Shortest Path in Nya Graph
题目大意:给你一个平面无向图,N个点,M条边。每条边都有一个边权cost,表示从这条边经过需要花费cost的代价。并且图中每个节点有一个等级,其中从等级x的点可以到达等级x+1或x-1的任意一个点,但是需要花费C。比方存在边(u,v),并且u的等级和v的等级相差1,那么从u到v可以选择花费cost到达也可以选择花费C到达。现在你的任务是找到一条从1到N的花费最小的路,输出花费,无解输出-1。
题目分析:
这题用到了一种思想,也是比较通用的思想:
将有影响的元素额外拉出来,然后按照关系建边。
就拿本题来说,每个节点有一个等级,那么我们为什么不将等级拉出来额外考虑呢?
对于每个节点u,他的等级为x,如果等级x+1存在,就建边(u,n + x + 1,C),如果等级x-1存在同理。
并且对于每个节点u,他的等级为x,那么建边(n + x,u,0)。
这样子处理以后,我们就成功将题目转化成求一次1到N的最短路即可。
虽然处理出来了,但是如果建边不当,依旧会TLE。
我们仔细观察可以发现,除了m条边必须双向外,其他的边单向足以。那么就有很多多余的边就可以剔除了。
因为这次我用的SPFA,对于本题,如果不加输入优化或者SPFA的SLF优化,那么G++ TLE,C++ 600+ms,
加了输入优化或者SLF优化G++ 500~600+ms
两个都加,可以成功优化到218ms。。。
不过能卡掉我不优化的代码可以说可能是我写的比较搓把。。。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REPV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define clear( a , x ) memset ( a , x , sizeof a )
const int MAXN = 100005 ;
const int MAXQ = 200005 ;
const int MAXE = 1000005 ;
const int INF = 0x3f3f3f3f ;
struct Edge {
int v , c , n ;
Edge () {}
Edge ( int var , int cost , int next ) :
v ( var ) , c ( cost ) , n ( next ) {}
} ;
Edge E[MAXE] ;
int hd[MAXN << 1] , cntE ;
int d[MAXN << 1] ;
int LV[MAXN] , vis[MAXN] ;
int Q[MAXQ] , head , tail ;
bool inq[MAXN << 1] ;
int NV , NE , C ;
void addedge ( int u , int v , int c ) {
E[cntE] = Edge ( v , c , hd[u] ) ;
hd[u] = cntE ++ ;
}
void read ( int &x ) {
x = 0 ;
char c = ' ' ;
while ( c < '0' || c > '9' )
c = getchar () ;
while ( c >= '0' && c <= '9' ) {
x = x * 10 + c - '0' ;
c = getchar () ;
}
}
void spfa () {
clear ( d , INF ) ;
clear ( inq , 0 ) ;
head = tail = 0 ;
d[1] = 0 ;
Q[tail ++] = 1 ;
while ( head != tail ) {
int u = Q[head ++] ;
if ( head == MAXQ )
head = 0 ;
inq[u] = 0 ;
for ( int i = hd[u] ; ~i ; i = E[i].n ) {
int v = E[i].v , val = d[u] + E[i].c ;
if ( d[v] > val ) {
d[v] = val ;
if ( !inq[v] ) {
inq[v] = 1 ;
if ( d[v] < d[Q[head]] ) {
Q[-- head] = v ;
if ( head == 0 )
head = MAXQ - 1 ;
}
else {
Q[tail ++] = v ;
if ( tail == MAXQ )
tail = 0 ;
}
}
}
}
}
}
void work () {
int u , v , c ;
cntE = 0 ;
clear ( hd , -1 ) ;
clear ( vis , 0 ) ;
read ( NV ) , read ( NE ) , read ( C ) ;
REPF ( i , 1 , NV ) {
read ( LV[i] ) ;
addedge ( NV + LV[i] , i , 0 ) ;
vis[LV[i]] = 1 ;
}
REPF ( i , 1 , NV ) {
if ( vis[LV[i] + 1] )
addedge ( i , NV + LV[i] + 1 , C ) ;
if ( vis[LV[i] - 1] )
addedge ( i , NV + LV[i] - 1 , C ) ;
}
REP ( i , NE ) {
read ( u ) , read ( v ) , read ( c ) ;
addedge ( u , v , c ) ;
addedge ( v , u , c ) ;
}
spfa () ;
if ( d[NV] == INF )
printf ( "-1\n" ) ;
else
printf ( "%d\n" , d[NV] ) ;
}
int main () {
int T , cas ;
for ( read ( T ) , cas = 1 ; cas <= T ; ++ cas ) {
printf ( "Case #%d: " , cas ) ;
work () ;
}
return 0 ;
}