E - Help Jimmy POJ - 1661 dp
E - Help Jimmy
这个题目本身不是很难,但是可以更加优化这个写法。
开始是n*n
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <algorithm> #include <cstdlib> #include <vector> #include <stack> #include <queue> #include <map> #include <string> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e3 + 10; int dp[maxn][2]; struct node { int l, r, h; node(int x = 0, int y = 0, int h = 0) :l(x), r(y), h(h) {} }ex[maxn]; bool cmp(node a, node b) { return a.h > b.h; } int main() { int t; scanf("%d", &t); while (t--) { int n, x, y, maxs, ans = inf, flag = 0; memset(dp, inf, sizeof(dp)); scanf("%d%d%d%d", &n, &x, &y, &maxs); for (int i = 1; i <= n; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); if (a > b) swap(a, b); ex[i] = node(a, b, w); } sort(ex + 1, ex + 1 + n, cmp); for (int i = 1; i <= n; i++) { if (ex[i].l <= x && ex[i].r >= x && ex[i].h <= y) { flag = 1; dp[i][0] = y - ex[i].h + abs(ex[i].l - x); dp[i][1] = y - ex[i].h + abs(ex[i].r - x); // printf("l=%d r=%d\n", ex[i].l, ex[i].r); // printf("dp[%d]=%d dp[%d]=%d %d\n", i, dp[i][0], i, dp[i][1], ex[i].h); break; } } if (flag == 0 && y <= maxs) { printf("%d\n", y); continue; } for (int i = 1; i <= n; i++) { int flag1 = 0, flag2 = 0; if (dp[i][0] >= inf || dp[i][1] >= inf) continue; for (int j = 1; j <= n; j++) { if (i == j) continue; if (ex[j].h > ex[i].h) continue; int h = ex[i].h - ex[j].h; if (h > maxs) continue; if (ex[i].l <= ex[j].r&&ex[i].l >= ex[j].l&&flag1 == 0) { flag1 = 1; dp[j][0] = min(dp[j][0], dp[i][0] + abs(ex[i].l - ex[j].l) + h); dp[j][1] = min(dp[j][1], dp[i][0] + abs(ex[i].l - ex[j].r) + h); // printf("l=%d l=%d h=%d\n", ex[i].l, ex[j].l, h); // printf("ww dp[%d][0]=%d dp[%d][1]=%d %d\n", j, dp[j][0], j, dp[j][1], ex[j].h); } if (ex[i].r <= ex[j].r&&ex[i].r >= ex[j].l&&flag2 == 0) { flag2 = 1; dp[j][0] = min(dp[j][0], dp[i][1] + abs(ex[i].r - ex[j].l) + h); dp[j][1] = min(dp[j][1], dp[i][1] + abs(ex[i].r - ex[j].r) + h); // printf("zz dp[%d][0]=%d dp[%d][1]=%d %d\n", j, dp[j][0], j, dp[j][1], ex[j].h); } } if (flag1 == 0 && ex[i].h <= maxs) ans = min(ans, dp[i][0] + ex[i].h); if (flag2 == 0 && ex[i].h <= maxs) ans = min(ans, dp[i][1] + ex[i].h); } printf("%d\n", ans); } return 0; }
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <algorithm> #include <cstdlib> #include <vector> #include <stack> #include <queue> #include <map> #include <string> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e3 + 10; int dp[maxn][2]; struct node { int l, r, h; node(int x = 0, int y = 0, int h = 0) :l(x), r(y), h(h) {} }ex[maxn]; bool cmp(node a,node b) { return a.h > b.h; } int main() { int t; scanf("%d", &t); while (t--) { int n, x, y, maxs, ans = inf; memset(dp, inf, sizeof(dp)); scanf("%d%d%d%d", &n, &x, &y, &maxs); for (int i = 1; i <= n; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); if (w >= y) continue; if (a > b) swap(a, b); ex[i] = node(a, b, w); } ex[++n] = node(x, x, y); ex[++n] = node(-inf, inf, 0); sort(ex + 1, ex + 1 + n, cmp); dp[1][0] = 0, dp[1][1] = 0; for (int i = 1; i <= n; i++) { int flag1 = 0, flag2 = 0; if (dp[i][0] >= inf || dp[i][1] >= inf) continue; for (int j = i+1; j <= n; j++) { if (ex[j].h >= ex[i].h) continue; int h = ex[i].h - ex[j].h; if (h > maxs) continue; if (ex[i].l <= ex[j].r&&ex[i].l >= ex[j].l&&flag1 == 0) { flag1 = 1; int val1 = abs(ex[i].l - ex[j].l); int val2 = abs(ex[i].l - ex[j].r); if (i == n || j == n) val1 = val2 = 0; dp[j][0] = min(dp[j][0], dp[i][0] + val1 + h); dp[j][1] = min(dp[j][1], dp[i][0] + val2 + h); // printf("l=%d l=%d h=%d\n", ex[i].l, ex[j].l, h); // printf("ww dp[%d][0]=%d dp[%d][1]=%d %d\n", j, dp[j][0], j, dp[j][1], ex[j].h); } if (ex[i].r <= ex[j].r&&ex[i].r >= ex[j].l&&flag2 == 0) { flag2 = 1; int val1 = abs(ex[i].r - ex[j].l); int val2 = abs(ex[i].r - ex[j].r); if (i == n || j == n) val1 = val2 = 0; dp[j][0] = min(dp[j][0], dp[i][1] + val1 + h); dp[j][1] = min(dp[j][1], dp[i][1] + val2 + h); // printf("zz dp[%d][0]=%d dp[%d][1]=%d %d\n", j, dp[j][0], j, dp[j][1], ex[j].h); } } } printf("%d\n", min(dp[n][0],dp[n][1])); } return 0; }
然后这个题目可以用线段树优化成 n*logn+n 的复杂度。
这个是因为每一个平台会落到的平台是固定的,所以可以用线段树预处理出来每一个平台的下一个平台。
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <string> #include <algorithm> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int M = 2e4 + 10; const int maxn = 2e3 + 10; struct node { int id, l, r, lx, rx, y; node(int id=0,int l=0,int r=0,int lx=0,int rx=0,int y=0):id(id),l(l),r(r),lx(lx),rx(rx),y(y){} }ex[maxn]; int p[maxn]; ll dp[maxn][2]; bool cmp(int a,int b) { return ex[a].y < ex[b].y; } bool cmp1(int a, int b) { return ex[a].y > ex[b].y; } int sum[M * 8], lazy[M * 8]; void build(int id,int l,int r) { sum[id] = lazy[id] = 0; if (l == r) return; int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); } void push_down(int id) { if (lazy[id] == 0) return; sum[id << 1] = lazy[id]; sum[id << 1 | 1] = lazy[id]; lazy[id << 1] = lazy[id << 1 | 1] = lazy[id]; lazy[id] = 0; } void update(int id,int l,int r,int x,int y,int val) { // printf("id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y); if(x<=l&&y>=r) { lazy[id] = val; sum[id] = val; return; } push_down(id); int mid = (l + r) >> 1; if (x <= mid) update(id << 1, l, mid, x, y, val); if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, val); } int query(int id,int l,int r,int pos) { if (l == r) return sum[id]; int mid = (l + r) >> 1; push_down(id); if (pos <= mid) return query(id << 1, l, mid, pos); return query(id << 1 | 1, mid + 1, r, pos); } int main() { int t; scanf("%d", &t); while(t--) { memset(dp, inf, sizeof(dp)); int N, X, Y, H; scanf("%d%d%d%d", &N, &X, &Y, &H); X += M; for(int i=1;i<=N;i++) { p[i] = i; int l, r, h; scanf("%d%d%d", &l, &r, &h); l += M, r += M; ex[i] = node(i, l, r, 0, 0, h); } N++; p[N] = N; ex[N] = node(0, -inf, inf, 0, 0, 0); build(1, 1, M * 2); sort(p + 1, p + 1 + N, cmp); for(int i=1;i<=N;i++) { // printf("i=%d p=%d\n", i, p[i]); int l = ex[p[i]].l, r = ex[p[i]].r, id = ex[p[i]].id; ex[p[i]].lx = query(1, 1, M*2, l); ex[p[i]].rx = query(1, 1, M*2, r); // printf("l=%d r=%d\n", l, r); // printf("ex[%d] lx=%d rx=%d\n", p[i], ex[p[i]].lx, ex[p[i]].rx); update(1, 1, M*2, l, r, id); } int num = query(1, 1, M*2, X); if(num==0) { printf("%d\n", Y); continue; } dp[num][0] = Y - ex[num].y + abs(X - ex[num].l); dp[num][1] = Y - ex[num].y + abs(X - ex[num].r); // printf("num=%d\n", num); // printf("dp[%d][0]=%lld dp[%d][1]=%lld\n\n", num, dp[num][0], num, dp[num][1]); sort(p + 1, p + 1 + N, cmp1); for(int i=1;i<=N;i++) { int id = ex[p[i]].id; // printf("p[%d]=%d id=%d\n", i, p[i], id); if (dp[id][0] >= inf) continue; int lx = ex[id].lx; int rx = ex[id].rx; if(ex[id].y-ex[lx].y<=H) { int val = abs(ex[id].l - ex[lx].l); if (lx == 0) val = 0; dp[lx][0] = min(dp[lx][0], dp[id][0] + ex[id].y - ex[lx].y + val); val = abs(ex[id].l - ex[lx].r); if (lx == 0) val = 0; dp[lx][1] = min(dp[lx][1], dp[id][0] + ex[id].y - ex[lx].y + val); } if(ex[id].y-ex[rx].y<=H) { int val = abs(ex[id].r - ex[rx].l); if (rx == 0) val = 0; dp[rx][0] = min(dp[rx][0], dp[id][1] + ex[id].y - ex[rx].y + val); val = abs(ex[id].r - ex[rx].r); if (rx == 0) val = 0; dp[rx][1] = min(dp[rx][1], dp[id][1] + ex[id].y - ex[rx].y + val); } // printf("dp[%d][0]=%lld dp[%d][1]=%lld\n", lx, dp[lx][0], lx, dp[lx][1]); // printf("dp[%d][0]=%lld dp[%d][1]=%lld\n\n", rx, dp[rx][0], rx, dp[rx][1]); } printf("%lld\n", min(dp[0][0], dp[0][1])); } return 0; }
还应该可以直接把dp放到线段树里面,就只有n*logn的复杂度。
这个暂时不想写了。