问题描述
给 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分): 有四个数据超时
决策
:
- 不选当前的数对:
dfs(u + 1, s1, s2)
- 选当前这个数对:
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 之和的最大值。
决策
:
- 不选当前的数:
f[i][j] = max(f[i][j], f[i - 1][j])
- 选当前这个数:
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:何时才能像大佬们一样优秀😒