您的位置:首页 > 其它

hdoj1176 免费馅饼(DP)

2016-03-23 01:41 330 查看

题解:

  动态规划,这一题实质上跟2084(数塔)那题是一样的,因为这一题可以转化成数塔问题,“馅饼掉下来的时刻”就是“塔的深度”,也就是dp数组的第1维;而第2维是一样的,都是表示位置。考虑题意给出的输入:

  Sample Input

  6

  5 1

  4 1

  6 1

  7 2

  7 2

  8 3

  0

  那么我们可以构造出一个数塔:

  第0层:     0[5]

  第1层:   1[4] 1[5] 1[6]

  第2层:           2[7]

  第3层:             1[8]

(没有画出来的元素都被初始化为0。因此,样例输入的答案为4。)

  而这道题虽然直观上而言,是从最顶部(第0层)的“下标为5的位置”(记为A)走到最底层(对应于下面代码中的第mDepth层),但是最后找答案的时候,不能保证最底层那个答案就是从A出发的,而这里可以用逆向思维来考虑,即“从A点出发到达最底层的最大值,就是从底层任意一点出发到达A点的最大值”,所以,代码中的循环是倒过来的,正如数塔问题的DP框架。另外,考虑到状态转移方程:

dp[i][j] += maxIn3(dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1])


要考虑数组越界问题,所以要将数组留够位置,而且最好把开始元素的下标从0都变成1。

代码(296ms, 7664KB):

#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

const int MAX_DEPTH(100002);
int dp[MAX_DEPTH][15];  // 注意,最好都从1开始,防止dp时数组越界
int mDepth; // 走到的最大的层数(深度)

int maxIn3(int a, int b, int c) {
a = (a > b ? a : b);
return (a > c ? a : c);
}

int main() {
//ifstream cin("in.txt");
ios::sync_with_stdio(false);    // 防止大输入超时
int num;
while (cin >> num && num) {
memset(dp, 0, sizeof dp);
mDepth = 0;
for (int i = 0; i < num; ++i) {
int atPos, atTime;
cin >> atPos >> atTime;
++dp[atTime][atPos + 1];    // 这里要处理下第2维的下标
if (atTime > mDepth) {
mDepth = atTime;
}
}

// 数塔dp
for (int i = mDepth - 1; i >= 0; --i) { // 倒过来变成完全的数塔。因为能走到起始位置的max,一定是从起始位置出发的max。
for (int j = 1; j <= 11; ++j) {
dp[i][j] += maxIn3(dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1]);
}
}
cout << dp[0][5+1] << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划