您的位置:首页 > 其它

hdu5361(最短路+并查集)

2016-07-07 21:14 211 查看
链接:点击打开链接

题意:有n个点排成一排,编号从1到n,每个点可以到自己[l, r]距离的位置,花费c,问一号店到其他点的最小花费

代码:#pragma comment(linker, "/STACK:102400000,102400000")
#include <set>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const long long INF=0x3f3f3f3f3f3f3f3f;
typedef pair<long long,int> P;
int V;
int l[500005],r[500005],par[500005];
long long d[500005],w[500005];
void init(int n){
int i;
for(i=0;i<=2*n;i++){
par[i]=i;
d[i]=INF;
}
}
int find(int x){
if(par[x]==x)
return par[x];
return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y)
return;
par[x]=y;
}
struct edge{
int to,cost;
};
void dijkstra(int s){
int i,j,v,le,re;
priority_queue<P,vector<P>,greater<P> >que;
d[s]=w[s]; //应该再加一个边权,如果用点的距离
que.push(P(d[s],s)); //则不知道应该再往哪走
while(!que.empty()){
P p=que.top(); que.pop();
v=p.second;
for(i=-1;i<=1;i+=2){
le=v+l[v]*i;
re=v+r[v]*i;
if(le>re)
swap(le,re);
le=max(1,le);
re=min(V,re);
for(j=le;j<=re;j++){
j=find(j); //用并查集找出当前点上一个区间最后一个点
if(j>re)
break;
if(d[j]>d[v]+w[j]){
d[j]=d[v]+w[j];
que.push(P(d[j],j));
}
unite(j,j+1);
}
}
}
}
int main(){ //因为每个点所连的边的权值都相等,因此每经过
int i,j,t; //一个点一定不会在经过第二次,所以问题就变为
scanf("%d",&t); //如何在最短路时直接找到没有更新过的点
while(t--){
scanf("%d",&V);
for(i=1;i<=V;i++)
scanf("%d",&l[i]);
for(i=1;i<=V;i++)
scanf("%d",&r[i]);
for(i=1;i<=V;i++)
scanf("%I64d",&w[i]);
init(V);
dijkstra(1);
for(i=1;i<V;i++){
if(d[i]==INF)
printf("-1 ");
else
printf("%I64d ",d[i]-w[i]);
}
if(d[V]==INF)
puts("-1");
else
printf("%I64d\n",d[V]-w[V]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: