传送门:【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 ; }