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