cqyz oj | 帮助Jimmy | DAG图

Description

  "Help Jimmy" 是在下图所示的场景上完成的游戏。
  
  场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。

  Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。

  设计一个程序,计算Jimmy到底地面时可能的最早时间。

Input

  第一行是四个整数N,X,Y,MAX,用空格分隔。

  N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。

  接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。

  Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。

  所有的平台均不重叠或相连。测试数据保证问题一定有解。

Output

  输出一个整数,Jimmy到底地面时可能的最早时间。

Sample Input 1 

3 8 17 20
0 10 8
0 10 13
4 14 3

Sample Output 1

23

Hint

1 <= N <= 1000,
-20000 <= X, X1[i], X2[i] <= 20000,
0 < H[i] < Y <= 20000(i = 1..N)。
所有坐标的单位都是米。

 
DAG图,只能从高往低保证了有向无环。
把平台的左端点和右端点分别看成图上的两个点,建图。
如果从当前这个边缘能到下面某个平台的边缘,连从当前的点到目标平台的左右边缘的点各一条边,
边权为 平台高度差+从这个点落到目标平台上后跑到边缘的距离。
出发点是当做左右边缘为都为X,高度为Y的平台
跑一个最短路即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#define lch(x) (x<<1)
#define rch(x) (x<<1|1)
using namespace std;
const int maxn = 1005, maxm = maxn*2, inf = 0x3f3f3f3f;

struct plf {
    int l, r;
    int h;
    friend bool operator < (const plf& a, const plf& b) {
        return a.h < b.h || (a.h == b.h && a.l < b.l);
    }
}a[maxn];

int fir[maxn*2], ne[maxm*2], to[maxm*2], w[maxm*2], np;
void add(int x, int y, int z) {
    ne[++np] = fir[x];
    fir[x] = np;
    to[np] = y;
    w[np] = z;
}

int n, MAX;
int X, Y;
void input() {
    cin >> n >> X >> Y >> MAX;
    for(int i=1, l, r, h; i<=n; i++) {
        scanf("%d%d%d", &l, &r, &h);
        a[i] = (plf){l, r, h};
    }
    a[++n] = (plf){X, X, Y};
}

int dis[maxn*2], inq[maxn*2];
void BFS(int s) {
    queue<int> Q;
    for(int i=0; i<=n*2; i++) dis[i] = inf, inq[i] = 0;
    dis[s] = 0; inq[s] = 1;
    Q.push(s);
    
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for(int i=fir[u]; i; i=ne[i]) {
            int v = to[i];
            if(dis[v] > dis[u] + w[i]) {
                dis[v] = dis[u] + w[i];
                if(!inq[v]) Q.push(v), inq[v] = 1;
            }
        }
    }
}

inline bool inRange(int x, int l, int r) { return l<=x && x<=r; }

void solve() {
    // 建图 
    sort(a+1, a+n+1);
    int ok1[maxn], ok2[maxn];
    
    for(int i=1; i<=n; i++) {
        ok1[i]=0, ok2[i]=0;
        for(int j=i-1; (!ok1[i] || !ok2[i]) && j>=1 && a[i].h - a[j].h <= MAX; j--) {
            if(!ok1[i] && inRange(a[i].l, a[j].l, a[j].r)) {
                add(lch(i), lch(j), (a[i].l - a[j].l) + (a[i].h - a[j].h));
                add(lch(i), rch(j), (a[j].r - a[i].l) + (a[i].h - a[j].h));
                ok1[i] = 1;
            }
            if(!ok2[i] && inRange(a[i].r, a[j].l, a[j].r)) {
                add(rch(i), lch(j), (a[i].r - a[j].l) + (a[i].h - a[j].h));
                add(rch(i), rch(j), (a[j].r - a[i].r) + (a[i].h - a[j].h));
                ok2[i] = 1;
            }
        }
    }
    
    // 特殊处理地面 
    for(int i=1; i<=n && a[i].h <= MAX; i++) {
        if(!ok1[i]) add(lch(i), 0, a[i].h);
        if(!ok2[i]) add(rch(i), 0, a[i].h);
    }
    
    int rt;
    for(rt=1; rt<=n; rt++)
        if(a[rt].l == X && a[rt].h == Y) break;
    
    BFS(lch(rt));
    printf("%d", dis[0]);
}

int main() {
    input();
    solve();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/de-compass/p/11822198.html