您的位置:首页 > 其它

hdu 1176

2016-07-18 21:23 162 查看

题目概述

有一数轴,有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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: