您的位置:首页 > 其它

hdu5361(2015多校6)--In Touch(变形的dijkstra)

2015-08-12 10:38 381 查看
题目链接:点击打开链接

题目大意:给出一个n个数的序列,标号为1到n,对于第i个数,它可以移动到距离i为[ li,ri ]的位置,花费为c[i],输入三行,第一行l[i],第二行r[i],第三行c[i],现在问对于第一个数来说,它移动到第i个位置的最小花费。(1<=i<=n)

这是一个每个点可以移动到一段中任意一个点,并且花费一样,这样就不适用与已有的四种最短路,但是可以对dijkstra进行变形,dij是每次找到一个距离最小的节点,用这个节点去更新其它节点,我们可以用一个优先队列,每次找到一个点,用这个点去更新其他的点,这个点要满足 dis[i]+c[i]是最小的,那么这个点更新出来的点也就是最小的。

有优先队列维护dis+c的值,用set来找到一段中还没有更新的点,这样就可以防止会遍历到已经更新好的点,造成超时。

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <algorithm>
using namespace std ;
#define LL __int64
#pragma comment(linker, "/STACK:102400000,102400000")
struct node{
int id ;
LL c ;
bool operator < (node a) const {
return c > a.c ;
}
} p , q ;
priority_queue<node> que ;
set<int> s ;
set<int> ::iterator iter ;
LL dis[200010] , c[200010] ;
int l[200010] , r[200010] ;
void f(int l,int r) {
iter = s.lower_bound(l) ;
while( iter != s.end() ) {
if( *iter > r ) break ;
dis[ *iter ] = p.c ;
q.id = *iter ;
q.c = p.c + c[ q.id ] ;
que.push( q ) ;
iter++ ;
s.erase(q.id) ;
}
return ;
}
int main() {
int t , n , i , x , y ;
//freopen("1009.in","r",stdin) ;
//freopen("111.out","w",stdout) ;
scanf("%d", &t) ;
while( t-- ) {

while( !que.empty() ) que.pop() ;
memset(dis,-1,sizeof(dis)) ;
s.clear() ;
scanf("%d", &n) ;

for(i = 2 ; i <= n ; i++) s.insert(i) ;
for(i = 1 ; i <= n ; i++) scanf("%d", &l[i]) ;
for(i = 1 ; i <= n ; i++) scanf("%d", &r[i]) ;
for(i = 1 ; i <= n ; i++) scanf("%I64d", &c[i]) ;
dis[1] = 0 ;
p.id = 1 ;
p.c = c[1] ;
que.push(p) ;
while( !que.empty() && !s.empty() ) {
p = que.top() ;
que.pop() ;
x = max(p.id - r[ p.id ],1) ;
y = p.id - l[ p.id ] ;
if( y >= 1 ) f(x,y) ;
x = p.id + l[ p.id ] ;
y = min(p.id + r[ p.id ],n) ;
if( x <= n ) f(x,y) ;

}
for(i = 1 ; i < n ; i++)
printf("%I64d ", dis[i]) ;
printf("%I64d\n", dis[i]) ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: