算法提高——求最大值

问题描述
给 n 个有序整数对 ai,bi,你需要选择一些整数对,使得所有你选定的数的 ai + bi 的和最大。

并且要求你选定的数对的 ai 之和非负,bi 之和非负。
  
输入格式
输入的第一行为 n,数对的个数
以下 n 行每行两个整数 ai,bi
  
输出格式
输出你选定的数对的 ai + bi 之和
  
样例输入
5
-403 -625
-847 901
-624 -708
-293 413
886 709

样例输出
1715

数据范围
1 ≤ n ≤ 100
-1000 ≤ ai,bi ≤ 1000


题解一
DFS(66分):
有四个数据超时

决策

  1. 不选当前的数对:dfs(u + 1, s1, s2)
  2. 选当前这个数对:dfs(u + 1, s1 + a[u], s2 + b[u])
#include <iostream>
#include <algorithm>
using namespace std;

int n, ans;
int a[110], b[110];

void dfs(int u, int s1, int s2)
{
	if(u == n + 1)
	{
		if(s1 >= 0 && s2 >= 0) ans = max(ans, s1 + s2);
		return;
	}
	
	dfs(u + 1, s1, s2); 
	dfs(u + 1, s1 + a[u], s2 + b[u]);
}

int main()
{
	cin >> n;
	
	for (int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
	
	dfs(1, 0, 0);
	
	cout << ans << endl;
	return 0;
}

ps:其实可以把 ai,bi 都小于 0 的数对去掉,因为加上它们只会让总和更小,然而这并不能让我再多过一个数据🤣

题解二
01背包:

f[i][j]:只从前 i 个数对中选,选定的 ai 之和为 j 时, bi 之和的最大值。

决策

  1. 不选当前的数:f[i][j] = max(f[i][j], f[i - 1][j])
  2. 选当前这个数:f[i][j] = max(f[i][j], f[i - 1][j - a[i]] + b[i])

边界处理:由于下标不能为负数,而 ai 可能为负数,因此要加上一个足够大的数,使 j 始终非负

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 110, MAXN = 200000;

int a[N], b[N];
int f[N][MAXN];

int main()
{
	int n;
	cin >> n;
	
	for (int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
	
	memset(f, -0x3f, sizeof f);
	
	int t = 100000;
	for (int i = 1; i <= n; i ++) f[i][t + a[i]] = b[i];
	
	for (int i = 1; i <= n; i ++)
		for (int j = 0; j <= MAXN; j ++)
		{
			f[i][j] = max(f[i][j], f[i - 1][j]);
			if(j - a[i] >= 0 && j - a[i] <= MAXN)                    // 转移前的状态也要合法 
				f[i][j] = max(f[i][j], f[i - 1][j - a[i]] + b[i]);
		}
		
	int ans = 0;
	for (int i = t; i <= MAXN; i ++)
		if(f[n][i] >= 0) ans = max(ans, f[n][i] + i - t);            // 加上 a[i] 之和,并减去偏移量 
	
	cout << ans << endl;
	return 0;
}

ps:何时才能像大佬们一样优秀😒

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值