week10作业C(拿数问题-动态规划)

题意

YJQ 上完第10周的程序设计思维与实践后,想到一个绝妙的主意,他对拿数问题做了一点小修改,使得这道题变成了 拿数问题 II。

给一个序列,里边有 n 个数,每一步能拿走一个数,比如拿第 i 个数, Ai = x,得到相应的分数 x,但拿掉这个 Ai 后,x+1 和 x-1 (如果有 Aj = x+1 或 Aj = x-1 存在) 就会变得不可拿(但是有 Aj = x 的话可以继续拿这个 x)。求最大分数。

输入说明:
第一行包含一个整数 n (1 ≤ n ≤ 105),表示数字里的元素的个数
第二行包含n个整数a1, a2, …, an (1 ≤ ai ≤ 105)
输出说明:
输出一个整数:n你能得到最大分值。

样例:
Input
2
1 2
Output
2
Input
3
1 2 3
Output
4
Input
9
1 2 1 3 2 2 2 2 3
Output
10

思路

  • 此题为动态规划问题,首先就是确定其转态,我们使用ma[i]来表示ma[i].va的分数;
  • 转态转移方程为ma[i]=max{ma[i-1],ma[i-2]+ma[i]},
  • 其次就是初始化,对于每一个ma[i]初始化其va和max_score的值,max_score为此分数*出现次数,va为此分数;
  • 结果为max{ma[i]}

总结

  • 第0项和第一项的处理要单独分开进行,但也可以通过参数的控制没有第0项;
  • 如果所有的分数都相同,则直接输出总分数即可,不需要进入转态转移模块;

代码

#include<iostream>
#include<algorithm>
using namespace std;
int a[100010];
struct node {
	long long int  va;
	long long int  max_score;
	bool operator<(const node& p)const {
		return max_score < p.max_score;
	}
} ma[100010];//为了存储最大分数
int n;
int count1 = 0;
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		scanf_s("%d", &a[i]);
	sort(a, a + n);//先进行排序
	//ma数组的初始化
	memset(ma, 0, sizeof ma);
	ma[0].max_score = a[0];
	ma[0].va = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] == a[i - 1])//先将与此值相等的加起来
		{
			ma[count1].max_score += a[i];
		}
		else
		{
			count1++;
			ma[count1].max_score += a[i];
			ma[count1].va = a[i];
		}
	}
	if (count1 == 0)
	{//所有的数都相等
		cout << ma[0].max_score << endl;
	}
	else
	{
		for (int i = 1; i <=count1; i++)
		{
			if (i == 1)
			{//动态规划中的特殊情况
				if (ma[1].va == ma[0].va + 1)
					ma[1].max_score = max(ma[0].max_score, ma[1].max_score); //等于x-1
				else
					ma[1].max_score = ma[1].max_score + ma[0].max_score;//不等于 x-1
			}
			else
			{
				if (ma[i].va == ma[i - 1].va+1)
					ma[i].max_score = max(ma[i - 1].max_score, ma[i - 2].max_score + ma[i].max_score);//如果i-1对应的值 等于x-1
				else
					ma[i].max_score = ma[i].max_score + ma[i - 1].max_score;//不等于则可以直接加即可
			}
		}
		sort(ma, ma + count1);
		cout << ma[count1].max_score << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值