E - Help Jimmy POJ - 1661 dp

E - Help Jimmy

 POJ - 1661 

这个题目本身不是很难,但是可以更加优化这个写法。

开始是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;
}
不把起点和终点当成平台的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;
        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*n

然后这个题目可以用线段树优化成 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;
}
线段树 n*logn+n

还应该可以直接把dp放到线段树里面,就只有n*logn的复杂度。

这个暂时不想写了。

 

posted @ 2019-08-20 21:55  EchoZQN  阅读(114)  评论(0编辑  收藏  举报