题目描述
小赛非常喜欢玩游戏,最近喜欢上了一个接金币的游戏。在游戏中,使用帽子左右移动接金币,金币接的越多越好,但是金币掉到地上就不能再接了。为了方便问题的描述,我们把电脑屏幕分成11格,帽子每次能左右移动一格。现在给电脑屏幕如图标上坐标:
也就是说在游戏里,金币都掉落在0-10这11个位置。开始时帽子刚开始在5这个位置,因此在第一秒,帽子只能接到4,5,6这三个位置中其中一个位置上的金币。问小赛在游戏中最多可能接到多少个金币?(假设帽子可以容纳无穷多个金币)。
输入
输入数据有多组。每组数据的第一行为以正整数n (0<n<100000),表示有n个金币掉在屏幕上上。在结下来的n行中,每行有两个整数x,T (0<T<100000),表示在第T秒有一个金币掉在x点上。同一秒钟在同一点上可能掉下多个金币。n=0时输入结束。输入数据以空格隔开
| 样例输入
7
|
输出
每一组输入数据对应一行输出。输出一个整数m,表示帽子最多可能接到m个金币。
| 样例输出
3 |
解题思路:看了一天的动态规划,终于解出了这道题,算是皇天不负有心人吧。
这个题目刚开始的时候真的是有点懵,取网上百度了一下题解,需要用到动态规划。于是开始了动态规划的学习历程。
下面就从动态规划的角度来讲解一下自己的思路:当下来金币的时候,小赛总会在他能够接近的三个(或者两个)位置,面临一个问题:接还是不接?接了的话,可能会在其他位置下来更多的,但是不在能够接近的范围内;但是不接的话,又会造成一定的损失(外一下一秒没有了怎么办)。从第一秒往最后一秒考虑的话,很难判断,因为你无法预判。但是如果我们从后往前考虑的话,就变得容易了。循环处理这11个位置,每次将下一秒三个位置(或两个位置)中较大值加到前一秒中。处理完后,dp[0][5]存储得就是我们想要得答案。
import java.util.Scanner;
public class Main {
public static int get_max(int a,int b,int c){
if(a>b)
b = a;
if (c>b)
b = c;
return b;
}
public static int dp_res(int[] a,int[] b,int max_second){
int m = max_second+1;
int n = 11;
int[][] dp = new int[m][n];
for(int i=0;i<a.length;i++)
dp[b[i]][a[i]]++;//同一秒钟在同一点上可能掉下多个金币
for(int i=m-2;i>=0;i--){
for(int j=0;j<11;j++){
//处理不同位置
if(j == 0){
dp[i][j] += Math.max(dp[i+1][j],dp[i+1][j+1]);
}else if(j==10){
dp[i][j] += Math.max(dp[i+1][j],dp[i+1][j-1]);
}else{
dp[i][j] += get_max(dp[i+1][j-1],dp[i+1][j],dp[i+1][j+1]);
}
}
}
return dp[0][5];
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];
int max_second = -999;
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
b[i] = sc.nextInt();
if(max_second<b[i])
max_second = b[i];
}
System.out.println(dp_res(a,b,max_second));
}
}
这个问题跟数塔问题,还是很像的,感兴趣的可以看一下我的那篇博客。
加油~~~