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; }