hdu 1176

来源:互联网 发布:nba新浪数据 编辑:程序博客网 时间:2024/05/16 07:11

题目概述

有一数轴,有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
原创粉丝点击