POJ 1661 Help Jimmy 最短路

http://poj.org/problem?id=1661

题意:一个人从(x,y)开始往下跳, 最高一次往下跳max, 中间有n个板子, 板子有左右端点位置和高度, 问最短多远到地面上.

思路:

考虑最短路

起点0, 每个板子左右端点共2*n个点, 地面设为2*n+1

建边:

起点能到的有两种情况: 1 第一个板子的左端点和右端点

                                      2 直接落到地上

中间的点能到的情况:    1  对于每个点(的左右端点)搜索下面能到的第一个板子(的左右端点)

                                      2 如果高度差超过max, 这个点的出边就建完了

                                      3 如果下面找不到板子, 看是否能落地

跑dijstra

代码:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const int M=2e5+5;
const int inf=1e9+5;
const int mod=1e9+7;
//memset(a,0x3f,sizeof(a));

int n,x,y,_max;
int s,e;

struct node {//板子
    int x1,x2,h;
} a[1005];

bool cmp(node a,node b) {
    return a.h>b.h;
}

struct node2 {//边
    int v,w;
    int nxt;
} edge[4005];
int head[2005];
int d[2005];
int ei;

void addedge(int u,int v,int w) {
    edge[ei].v=v,edge[ei].w=w;
    edge[ei].nxt=head[u];
    head[u]=ei++;
}

struct HeapNode {
    ll d, u;
    bool operator < (const HeapNode& rhs)const {
        return d>rhs.d;
    }
};
priority_queue<HeapNode>Q;
bool done[12005] = { 0 };

void dj() {
    for (int i = 0; i <=2*n+1; i++)
        d[i] = inf;
    d[s] = 0;
    Q.push(HeapNode{ 0,s });
    while (!Q.empty()) {
        HeapNode x = Q.top();
        Q.pop();
        int u = x.u;
        if (done[u])
            continue;
        done[u] = 1;
        for (int i = head[u]; i != -1; i = edge[i].nxt) {
            node2&e = edge[i];
            if (d[e.v]>d[u] + e.w) {
                d[e.v] = d[u] + e.w;
                Q.push(HeapNode{ d[e.v],e.v });
            }
        }
    }
}

void Addedge() {
    s=0,e=2*n+1;
    int f3=0;//起点下有无板子
    for(int i=1; i<=n; i++) {
        if(a[i].x1<=x&&x<=a[i].x2) {
            f3=1;
            addedge(s,i,x-a[i].x1);//1->n表示所有板子的左端点
            addedge(s,i+n,a[i].x2-x);//1+n->n+n表示所有板子的右端点
            break;
        }
    }
    if(f3==0)
        addedge(0,2*n+1,0);
    for(int i=1; i<=n; i++) {
        int f1=0,f2=0;//这个板子的左端点/右端点下方有没有板子接着
        for(int j=i+1; j<=n; j++) {
            if(a[j].h==a[i].h)
                continue;
            if(a[i].h-a[j].h>_max)
                break;
            int l=a[i].x1,r=a[i].x2;
            if(l>=a[j].x1&&l<=a[j].x2&&!f1) {
                f1=1;
                addedge(i,j,l-a[j].x1);
                addedge(i,j+n,a[j].x2-l);
            }
            if(r>=a[j].x1&&r<=a[j].x2&&!f2) {
                f2=1;
                addedge(i+n,j,r-a[j].x1);
                addedge(i+n,j+n,a[j].x2-r);
            }
        }
        if(f1==0) {
            if(a[i].h<=_max) {
                addedge(i,e,0);
            }
        }
        if(f2==0) {
            if(a[i].h<=_max) {
                addedge(i+n,e,0);
            }
        }
    }
}

void init(){
    ei=0;
    memset(done, 0, sizeof(done));
    memset(head, -1, sizeof(head));
    while (!Q.empty())
        Q.pop();
}

int main() {
    int _;
    scanf("%d",&_);
    while(_--) {
        init();
        scanf("%d%d%d%d",&n,&x,&y,&_max);
        for(int i=1; i<=n; i++) {
            scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
        }
        sort(a+1,a+n+1,cmp);
        Addedge();
        dj();                 //垂直高度其实与如何走是无关的,永远是y
        printf("%d\n",d[e]+y);//所以dj时只算水平距离的最短路即可
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值