初学dp,写的不好请多包涵,thanks!!
先上题目。。。
题目描述
小明今天非常无聊,他在纸上写了n个1~n之间的整数。他每次可以划掉其中没被划掉的一个整数x,若如此做,也必须划掉等于x-1和x+1的所有整数,并且得到x分。他想知道他最多能得到多少分?
输入输出格式
输入格式:
第一行一个数字n
第二行n个在1~n之间的整数。
输出格式:
一个整数表示最大得分
输入输出样例
输入样例#1:
5
1 2 3 4 5
输出样例#1:
9
输入样例#2:
10
1 2 3 1 2 2 1 3 2 2
输出样例#2:
10
说明
样例解释
在第一个样例中,我们先划掉5(同时划掉4),3(同时划掉2),1,可以得到9分。
在第二个样例中,我们先划掉一个2,此时所有的1和3都被划掉,剩下的2我们全部划掉,可以得到10分。
数据范围
对于100%的数据n<=100000
拿到一个题目,先理解题意:给你n个1--n范围内的数(并不是1--n,的都包括也有重复的数),要你取一个整数,得分就是这个整数的值,且与这个整数相邻的两个整数就不能再取了,题目就让你取啊取啊,找到最大的得分。
思路:每个数可以取也可以不取,那么我们就吧每个数取得时候的的最大得分和不取的时候的最大得分计算出来,最后挑出一个最优解输出就可以了,这个计算的过程就是用动态规划来实现的。
实现方法:dp[i][1]表示取i这个数时1--i的最大得分,dp[i][0]就是不取这个数的1--i时的最大得分,用num[i]记录这个数出现了多少次,以防止重复的数只加一次,然后就是状态转移了。dp[i][1]是取i这个数,能取i这个数代表i-1这个数肯定没取,因为相邻的两个数不能取,这是题目要求,如果i-1这个数取了,那i肯定是不能取的。所以dp[i][1]的状态转移方程就是dp[i-1][0]+num[i]*i,表示上一个数不取的情况下加上现在去这个点的收益;dp[i][0]呢?想一想不取i这个点,那么状态可能是取了上个点或不取上个点,这两种情况都是和题目要求不冲突的,但由于要求得分尽量大,所以就取最大值,由于不取i这个点,所以i这个点不造成收益,所以状态转移方程就是max(dp[i-1][0],dp[i-1][1]),那么代码如下。。
灰常短
#include<iostream>
#include<algorithm>
using namespace std;
int n, a[100010] = {}, dp[100010][2] = {}, maxe = -1, num[100010];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
num[a[i]]++;//统计i个数
}
//核心语句
for (int i = 1; i <= n; i++) {
dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
if (maxe < dp[i][0])maxe = dp[i][0];
dp[i][1] = dp[i - 1][0] + num[i] * i;
if (maxe < dp[i][1])maxe = dp[i][1];
}
cout << maxe << endl;
return 0;
}
网友评论