poj 3377 Ferry Lanes(dij+heap)

33 篇文章 0 订阅
13 篇文章 0 订阅
Ferry Lanes
Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 4070 Accepted: 866

Description

Arthur lives in a small city which is partitioned into two districts, the northern and the southern, by a river flowing through. The northern and southern districts are connected by N + 1 bidirectional ferry lanes, numbered 0 to N from west to east. Each ferry lane connects two docks in separate sides of the river. No two lanes share the same dock or cross each other.

Today Arthur needs to deliver a package from one dock to another. He knows the sailing time of each ferry lane and the time cost by walking from one dock to an adjacent one along the river bank. Arthur wants to know what is the minimum time his delivery will cost.

Input

The input consists of several test cases. The first line of each consists an integer N ( 1 ≤ N ≤ 1,000,000). The second line consists of two pairs of integers describing the starting and finishing docks, where the first of each pair represents the district (0 means northern and 1 means southern) and the second represents the lane number. The third line contains N integers describing the time cost by walking between two adjacent docks on the northern bank from lane0 to laneN. The fourth line contains N + 1 integers describing the sailing time of each ferry lane. The last line contains N integers describing the time cost by walking between two adjacent docks on the southern bank from lane0 to laneN. N = 0 indicates the end of input.

Output

For each test cases output one line contains the minimum time. You may assume the answer fits in a signed 64-bit integer.

Sample Input

4
0 0 1 4
1 3 5 7
3 5 1 3 7
1 3 7 5
0

Sample Output

17
 
题意:一条河,南北两岸各有编号为0~n的共n+1个船坞。面对面的船坞有航线相连。给出每条航线所用的时间和人沿岸走到相邻船坞所用时间,求人从起点到终点所用最小时间。
思路:一个无向图求最短路径。图中顶点过多,直接建图不现实。我们可以根据所在点的位置扩展,进行松弛,将新的边加入优先队列中。类似BFS的解法。
 
AC代码:
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <iostream>
#define max2(a,b) ((a) > (b) ? (a) : (b))
#define min2(a,b) ((a) < (b) ? (a) : (b))

using namespace std;

const int maxn=1000005;

struct node
{
    int u;
    long long dis;
    bool operator < (const node &a) const
    {
        return dis>a.dis;
    }
}cur,next;
int n,start,end;
int ndis[maxn],sdis[maxn],ferry[maxn];
bool vis[2*maxn];
priority_queue<node> Q;
void relex(int v,int len)
{
    next.u=v;
    next.dis=cur.dis+len;
    Q.push(next);
}
long long dij()
{
    memset(vis,false,sizeof(vis));
    while(!Q.empty()) Q.pop();
    cur.u=start;
    cur.dis=0;
    Q.push(cur);
    while(!Q.empty())
    {
        cur=Q.top();
        Q.pop();
        if(cur.u==end) return cur.dis;
        if(vis[cur.u]) continue;
        vis[cur.u]=true;
        if(cur.u==0)   //点在北岸的最左边
        {
            relex(1,ndis[1]);
            relex(n+1,ferry[0]);
        }
        else if(cur.u==n)   //点在北岸的最右边
        {
            relex(n-1,ndis[n]);
            relex(2*n+1,ferry[n]);
        }
        else if(cur.u>0&&cur.u<n)  //点在北岸,但不在最右或最左
        { 
            relex(cur.u-1,ndis[cur.u]);
            relex(cur.u+1,ndis[cur.u+1]);
            relex(cur.u+n+1,ferry[cur.u]);
        }
        else if(cur.u==n+1)     //点在南岸最左边
        {
            relex(n+2,sdis[1]);
            relex(0,ferry[0]);
        }
        else if(cur.u==2*n+1)    //点在南岸最右边
        {
            relex(2*n,sdis[n]);
            relex(n,ferry[n]);
        }
        else if(cur.u>n+1&&cur.u<2*n+1)   点在南岸,但不在最右或最左
        {
            relex(cur.u-1,sdis[cur.u-n-1]);
            relex(cur.u+1,sdis[cur.u-n]);
            relex(cur.u-n-1,ferry[cur.u-n-1]);
        }
    }
    return -1;
}
int main()
{
    int a,b,c,d;
    while(scanf("%d",&n),n)
    {
    scanf("%d%d%d%d",&a,&b,&c,&d);
    if(a==0) start=b;
    else start=b+n+1;
    if(c==0) end=d;
    else end=d+n+1;
    for(int i=1;i<=n;i++)
    scanf("%d",&ndis[i]);
    for(int i=0;i<=n;i++)
    scanf("%d",&ferry[i]);
    for(int i=1;i<=n;i++)
    scanf("%d",&sdis[i]);
    printf("%lld\n",dij());
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值