免费馅饼(HDU-1176)

6 篇文章 0 订阅
5 篇文章 0 订阅

题目链接:
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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值