1.题目描述:
After several latest reforms many tourists are planning to visit Berland, and Berland people understood that it's an opportunity to earn money and changed their jobs to attract tourists. Petya, for example, left the IT corporation he had been working for and started to sell souvenirs at the market.
This morning, as usual, Petya will come to the market. Petya has n different souvenirs to sell; ith souvenir is characterised by its weight wiand cost ci. Petya knows that he might not be able to carry all the souvenirs to the market. So Petya wants to choose a subset of souvenirs such that its total weight is not greater than m, and total cost is maximum possible.
Help Petya to determine maximum possible total cost.
The first line contains two integers n and m (1 ≤ n ≤ 100000, 1 ≤ m ≤ 300000) — the number of Petya's souvenirs and total weight that he can carry to the market.
Then n lines follow. ith line contains two integers wi and ci (1 ≤ wi ≤ 3, 1 ≤ ci ≤ 109) — the weight and the cost of ith souvenir.
Print one number — maximum possible total cost of souvenirs that Petya can carry to the market.
1 1 2 1
0
2 2 1 3 2 2
3
4 3 3 10 2 7 2 8 1 1
10
2.题意概述:
有n个物品,背包容量为m。
每个物品只会有1,2,3个单位占有空间,价值为c。
现在问如何可以使拿到的物品的价值最大。
3.解题思路:
标准的01背包问题,只是数据非常的大,貌似用现有的背包dp方式好像没有什么办法解决。然而,发现物品的质量只有1、2、3,这是一个非常有用的信息。根据背包的质量,我们转移的时候的转移方式就非常的有限。
然而,本文的主角并不是这个dp,这个dp只能说算称之为背包dp的一种。接下来重点讲一下三分法。首先,还是利用它只有三种质量的物品这个性质,同样可以枚举取每种质量物品的个数。最暴力的想法莫过于枚举质量为3和2的物品个数,但是O(n^2)的复杂度不可接受。于是我们就想,我枚举质量为3的物品个数,然后二分质量为2的物品个数可以吗?我们知道,用二分的前提条件是要有单调性,但是,这种情况下并没有,因为当质量为2的物品个数多了,相应的质量为1的物品个数就少了。然而,经过分析,我们发现这个函数很像一个二次函数,即有一个顶点,而且可以证明,函数是先增后减,即含有最大值的。于是,我们就想到了类似二分的方法——三分法。(图侵删)如图,我们根据左右端点确定一个lmid,然后再根据lmid和r确定rmid,比较lmid和rmid两点的函数值,由图可分成两种情况:当f(lmid)>f(rmid)时,结果肯定在l和rmid之间;当f(lmid)<f(rmid)的时候,结果肯定在lmid和r之间,然后利用这个不断三分逼近ans就可以得到结果。可以看到,这个和二分法其实很类似,不同的地方就在单调性不同,三分法几乎可以使用与所有的连续函数,当然前提是限定区间内只有一个极值。当然本题还有一个贪心的方法:(转自:codeforces808e)这种做法以后再补QAQ
贪心的思想,在相同的占有空间的时候,一定选价值最大的。所以给物品排一个序。dp第1,2种单位的占有空间,每次可以通过dp[i - 1].s1和dp[i - 2].s2来知道当前已经用到了第多少个第1,2种单位的物品。然后所有都dp完之后,第三种物品尽可能的选,看看什么情况价值最大就可以了。
4.AC代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100100
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
vector<int> p[4];
ll sum[4][maxn];
int sz[4];
ll f(int x, int i, int m)
{
return sum[2][x] + sum[1][min(sz[1], m - i * 3 - x * 2)];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int n, m;
while (~scanf("%d%d", &n, &m))
{
for (int i = 1; i <= 3; i++)
p[i].clear();
for (int i = 0; i < n; i++)
{
int c, w;
scanf("%d%d", &w, &c);
p[w].push_back(c);
}
for (int i = 1; i <= 3; i++)
{
sz[i] = p[i].size();
sort(p[i].begin(), p[i].end(), greater<int>());
sum[i][0] = 0;
for (int j = 0; j < sz[i]; j++)
sum[i][j + 1] = sum[i][j] + p[i][j];
}
ll ans = 0;
int cnt = min(sz[3], m / 3);
for (int i = 0; i <= cnt; i++)
{
int l = 0, r = min((m - i * 3) / 2, sz[2]);
while (r - l > 1)
{
int mid = l + r >> 1;
int mmid = mid + r >> 1;
if (f(mid, i, m) > f(mmid, i, m))
r = mmid;
else
l = mid;
}
ans = max(ans, max(f(l, i, m), f(r, i, m)) + sum[3][i]);
}
printf("%lld\n", ans);
}
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}