hdu 1176

题目概述

有一数轴,有0到10共11个位置,某人在第0秒时站在5位置,每秒至多移动1个位置,数轴的11个位置上空会不定时落下一张馅饼,但一定在每秒人移动后掉落,人只能接住自己移动后所在位置的馅饼,给出其降落的位置a和着陆的时刻b,求最多可接住多少馅饼

时限

1000ms/2000ms

输入

每组数据第一个正整数N,其后N行,每行两个正整数a,b,输入以N=0结束

限制

1<=N<=100000;1<=b<=100000;同一秒的同一位置可能会掉下多张馅饼

输出

每行一个数,最多接住的馅饼数

样例输入

6
5 1
4 1
6 1
7 2
7 2
8 3
0

样例输出

4

讨论

dp,题目说的很复杂,换个说法,一个11*100001的矩阵中每个位置有一非负整数,从第5行第0列出发,每次可向右上,右,右下移动一格并获得该位置的数字,求到矩阵右边界时可得数字的最大和,这个描述很熟悉呀,经典的矩阵移动呀,和hdu 2571差不多呀,好办了
矩阵移动的题都是一个思想,倒推,子问题是将起点右移到某个位置时可得最大和,子问题边界是将起点移到矩阵右边界某位置时可得最大和,绝无后效性,转移方程依然标注在代码中,dp完成后返回起点位置的值即是结果
代码经过了一点优化,因而关键部分不是很直观

题解状态

78MS,6024K,778 B,C++

题解代码

#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 100003
#define memset0(a) memset(a,0,sizeof(a))

int mat[11][MAXN];//存放原始数据 由于可能同一时间同一位置多个饼 故不用bool型
int dp[11][2];//dp辅助矩阵 由于每次仅参考右侧一列 因而2列足矣
int fun(int N)
{
    int time = 0;//记录最晚的降落时刻
    for (int p = 0; p < N; p++) {
        int a, b;//位置 时刻
        scanf("%d%d", &a, &b);//input
        time = max(time, b);
        mat[a][b]++;//同一时间同一位置的饼数+1
    }
    for (int p = time; p >= 0; p--) {//从最晚的饼开始倒序处理
        int o = (p + 1) % 2;//简化运算 将需要在max函数中计算4次的取模运算一次解决
        for (int i = 0; i <= 10; i++)
            dp[i][!o] = max({ i ? dp[i - 1][o] : 0,dp[i][o] ,i < 10 ? dp[i + 1][o] : 0 }) + mat[i][p];//重要的转移方程 原本形式是这个dp[i][p] = max({ i - 1 >= 0 ? dp[i - 1][p + 1] : 0,dp[i][p + 1] ,i - 1 <= 10 ? dp[i + 1][p + 1] : 0 }) + mat[i][p]; 无非就是从下一秒可到达的三个位置/矩阵右侧三个位置的dp值中选一个最佳的 顺便排除掉越界的情况
    }
    return dp[5][0];//返回起点的时间和位置 矩阵移动的题都这么做
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int N;
    while (~scanf("%d", &N) && N) {//input
        printf("%d\n", fun(N));//output
        memset0(dp);//dp数组总是要清零
        memset0(mat);//由于是采用加的方式得到原始数据 因而也需要清零
    }
}

EOF

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值