HDU-4362 Dragon Ball DP+优化

这题如果采用普通的DP方程的话果断TLE。所以需要对DP方程进行优化。

由于这里龙珠可以随意选取,所以龙珠的编号也就没有了什么意义了,所以直接先对龙珠进行排序,我们只要保证其位置和花费同步排序就可以了。

接下来就是优化了,这个部分可以见代码,在上一题中使用的同步滑动指针,这里则不然,需要根据数值来异步滑动指针。

代码如下:

#include <cstdlib>

#include <cstring>

#include <cstdio>

#include <algorithm>

#define INF 0x7f7f7f7f

using namespace std;



int N, M, x, dp[55][1005];

// dp[i][j] 代表第i时刻选择j号物品的最小值 

struct Node

{

    int pos, ti;

    bool operator < (Node temp) const

    {

        return pos < temp.pos;    

    }

}e[55][1005];



// dp[i][j] 表示i时刻拿j个龙珠的最少花费

// 完整的dp方程是 dp[i][j] = min( dp[i-1][k] - abs(loc[i][j] - loc[i-1][k]) + ti[i][j] )

// 当 loc[i][j] < loc[i-1][k]

// 方程变为 dp[i][j] = min( dp[i-1][k] + loc[i][j] - loc[i-1][k] + ti[i][j])

// 显然此时只要求得 dp[i-1][k] - loc[i-1][k] 的最小值来递推便可了

// 同理当 loc[i][j] > loc[i-1][k]

// 方程变为 dp[i][j] = min( dp[i-1][k] - loc[i][j] + loc[i-1][k] + ti[i][j])

// 显然此时只要求得 dp[i-1][k] + loc[i-1][k] 的最小值来递推便可了



void read()

{

    for (int i = 1; i <= M; ++i) {

        for (int j = 1; j <= N; ++j) {

            scanf("%d", &e[i][j].pos);

        }

    }

    for (int i = 1; i <= M; ++i) {

        for (int j = 1; j <= N; ++j) {

            scanf("%d", &e[i][j].ti);

        }

        sort(e[i]+1, e[i]+N+1);  // 对所有的坐标进行排序

    }

}



void DP()

{

    int Min, k;

    memset(dp, 0x7f, sizeof (dp));

    for (int i = 1; i <= N; ++i) {

        dp[0][i] = 0;

        e[0][i].pos = x;

    }

    for (int i = 1; i <= M; ++i) {

        k = -1;

        Min = INF; // 假设是从该点的左边的递推过来

        // 由于给定的点不一定满足 ptr < j,那么前面的点的坐标一定小于后面的点 

        // 所以要进行一次排序,来使得其满足上述的性质,这样才能够使得dp[i][j]能够取到最优值

        for (int j = 1, ptr = 1; j <= N; ++j) {

            while (ptr <= N && e[i-1][ptr].pos <= e[i][j].pos) {

                if (Min > dp[i-1][ptr] - e[i-1][ptr].pos) {

                    Min = dp[i-1][ptr] - e[i-1][ptr].pos;

                    k = j;

                }

                ++ptr;

            }

            if (k != -1) {

                dp[i][j] = Min + e[i][j].pos + e[i][j].ti;

            }

        }

        k = -1;

        Min = INF;

        for (int j = N, ptr = N; j >= 1; --j) {

            while (ptr >= 1 && e[i-1][ptr].pos > e[i][j].pos) {

                if (Min > dp[i-1][ptr] + e[i-1][ptr].pos) { 

                    Min = dp[i-1][ptr] + e[i-1][ptr].pos;

                    k = j;

                }

                --ptr;

            }

            if (k != -1) {

                dp[i][j] = min(dp[i][j], Min - e[i][j].pos + e[i][j].ti);

            }

        }

    }

    Min = INF;

    for (int i = 1; i <= N; ++i) {

        Min = min(Min, dp[M][i]);

    }

    printf("%d\n", Min);

}



int main()

{

    int T;

    scanf("%d", &T);

    while (T--) {

        scanf("%d %d %d", &M, &N, &x);

        read();

        DP();

    }

    return 0;

}

你可能感兴趣的:(drag)