题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1176
题目大意:
gameboy最开始在坐标 5上,他只能在0-10坐标移动,且在 i 位置的gameboy 在下一秒只能接(i-1),(i),(i+1)中一个位置的馅饼(这时刻掉下的馅饼可能不止一个),求最终她最多能接多少馅饼
题目分析:
大佬都把这个题归类为数塔问题,如果做过数塔的同学应该可能,也许会做…(数塔最基础的问题不难,可以去看一下),
但是像我就是看了数塔,也不能一下子明白这个题要怎么写,算法的高级问题就在这,你可能不能一下子看出来他要用什么算法,就算别人告诉你这个 要用什么算法,你可能也一下子想不太明白…(废话有点多),理解了数塔,但还不是很了解这个题的做法的就可以画一下图,慢慢来,应该可以明白。
这里没有讲的很细致,只是把我自己碰到的问题拿出来给大家分享一下,可能讲的也不是太好,谅解谅解!!
看了很多别人写的代码都是逆着来推的,结合数塔模型可以写出这个代码(已AC),代码如下:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
//应该先了解一下数塔,
const int N=100005;
int dp[N][12];
int main()
{
int n;
int x,T;
while(scanf("%d",&n)==1&&n!=0)
{
memset(dp,0,sizeof(dp));
int m=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&T);
dp[T][x]++;
if(T>m)
m=T;
}
for(int i=m-1;i>=0;i--)//时间
for(int j=0;j<11;j++)//位置
{
if(j==0)
dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);
else if(j==10)
dp[i][j]+=max(dp[i+1][j-1],dp[i+1][j]);
else
dp[i][j]+=max(dp[i+1][j-1],max(dp[i+1][j],dp[i+1][j+1]));
}
printf("%d\n",dp[0][5]);
}
return 0;
}
但是,像我当时我就觉得这个题是可以正推的,然后我就简单想了一下,写出下面这个错误代码,果然想的简单了,我觉得应该可能会有人像我一样吧,所以我就把他贴出来了(错误代码),代码如下:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=100005;
int dp[N][12];
int main()
{
int n;
int x,T;
while(scanf("%d",&n)==1&&n!=0)
{
memset(dp,0,sizeof(dp));
int m=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&T);
dp[T][x]++;
if(T>m)
m=T;
}
for(int i=1;i<=m;i++)//时间
for(int j=0;j<11;j++)//位置
dp[i][j]+=max(dp[i-1][j-1],max(dp[i-1][j],dp[i-1][j+1]));//这里会出现越界的情况,有的时候会AC不了,这里我没写,大家记得要写,具体怎么写,上面那个代码可参考
printf("%d\n",dp[0][5]);
}
return 0;
}
一看这个代码是不是觉得问题不大,应该能过
nonono ,这个思路就不是一个正确的思路,要记住题目是要我们以 坐标 5出发,最终算出馅饼可得的最大值,而这个代码已经不是原来的思想了,它现在的意义是 各个点出发,然后最终到达 坐标 5 可得馅饼数最大的值。
其实这里我想了很久,最后找我们班大佬问的,其实不管是 逆推 还是 正推 我们都是要 求dp[0][5] (0秒时刻,位置为5),下面附上大佬写的代码(已AC)(顺推):
# include <stdio.h>
# include <algorithm>
# include <cstring>
# define max3(a,b,c) max(max((a),(b)),(c))
using namespace std;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
int n;
int dp[12][maxn];
int main() {
while(scanf("%d",&n) != EOF) {
if(!n) break;
int MAX_TIME = 0;
memset(dp,0,sizeof dp);
for(int i = 0; i < n; i++) {
int a, b;//a表示位置,b表示时间。
scanf("%d%d",&a,&b);
dp[a][b]++;
MAX_TIME = max(MAX_TIME,b);
}
for(int i = 0; i <= 11; i++) {
if(i >= 4 && i <= 6) ;
else dp[i][1] = -INF;
}
for(int j = 2; j <= MAX_TIME; j++) {
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] += max3(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1]);
}
}
int MAX = 0;
for(int i = 0; i <= 10; i++) {
if(dp[i][MAX_TIME] > MAX) MAX = dp[i][MAX_TIME];
}
printf("%d\n",MAX);
}
return 0;
}