由数塔引出。
数塔:
处于一个端点,每次可以选择向左或向右。
而每次选择,取决于,向左能够得到最大值,还是向右能得到最大值。
当到达数塔倒数第二行时,向左还是向右,仅仅取决于,向左的端点数值大还是向右的大。
自顶向下思考,自底向上计算。
将数塔倾斜,用i,j表示在数塔中位置,dp[ i ][ j ]则表示在为位置( i , j )时,能够得到的最大值。
得到 1.递推公式 dp[ i ][ j ] = max(dp[ i + 1 ][ j ],dp[ i ][ j + 1 ]) + num[ i ][ j ];
2.边界条件 dp[ n - j + 1][ j ] = num[ j ] ( j = 1 to n )
//即dp[n][0] = num[0],dp[n - 1][1] = num[1]...
免费馅饼 hdu1176
假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
输入数据有多组。每组数据的第一行为以正整数n(0<n<100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0<T<100000),表示在第T秒有一个馅饼掉在x点上。同一秒钟在同一点上可能掉下多个馅饼。n=0时输入结束。
求表示gameboy最多接到几个馅饼?
分析:
处于一个位置,每次可以选择向左,向右,或者不动。
每次的选择,依然取决于,向左,向右,不动,哪个选择能使,达到最大值。
当时间在倒数第二秒时,每次选择,仅取决于,下一秒,3个位置中的哪个位置,会得到最大值。
仍然用i,j表示在这个树中的位置,i 表示位置(0 ~ 10),j表示时间,dp[ i ][ j ]表示,在时间j,位置i所能得到的最大值。
得到 1.递推公式 dp[ i ][ j ] = max(dp[ i - 1][ j + 1 ],dp[ i ][ j + 1 ],dp[ i + 1 ][ j + 1 ]) + 在时刻j,位置i所落下的馅饼数
//注意i,j不要越界
2.边界条件 dp[ i ][ last_time ] = 在last_time最后一刻,位置i落下的馅饼数
#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
const int maxt = 100005;
int dp[12][maxt];
void solve(int last_time,map<int, vector<int>> &mp)
{
for (int j = last_time; j >= 0; j --) {
vector<int> &v = mp[j];
if (j == last_time) {
for (int k = 0; k < v.size(); k ++) {
dp[v[k]][j] ++;
}
}
else {
for (int i = 0; i <= 10; i ++) {
if (i == 0) {
dp[i][j] = max(dp[i][j + 1],dp[i + 1][j + 1]);
}
else if(i == 10)
dp[i][j] = max(dp[i][j + 1],dp[i - 1][j + 1]);
else dp[i][j] = max(dp[i][j + 1], max(dp[i + 1][j + 1],dp[i - 1][j + 1]));
}
for (int k = 0; k < v.size(); k ++) {
dp[v[k]][j] ++;
}
}
}
}
int main()
{
int n;
int x,t;
while (scanf("%d",&n) != EOF && n) {
map<int, vector<int>> mp;
memset(dp, 0, sizeof(dp));
int last_time = 0;
for (int i = 0; i < n; i ++) {
scanf("%d%d",&x,&t);
last_time = max(last_time, t);
mp[t].push_back(x);
}
solve(last_time, mp);
printf("%d\n",dp[5][0]);
}
return 0;
}