背包问题(bag)
题目描述:
输入:
从文件 bag.in 中读入数据。
单个测试点中包含多组数据,输入第一行为一个非负整数 T,描述数据组数。接下来依次描述每组数据,对于每组数据:
第一行一个非负整数 n,描述物品数量。
第 2 行至第 n + 1 行,每行两个用空格隔开的正整数,其中第 i + 1 行的两个数依次为 wi, vi,分别描述第 i 个物品的重量和价值。
接下来一行一个非负整数 m,描述背包数量。
接下来一行 m 个用空格隔开的正整数 t1, . . . , tm,依次描述各背包的承重上限。
输出:
输出到文件 bag.out 中。
一行一个整数,表示能够选出的物品数量的最大值。
这道题考场想到了,但是写挂了。
然后跟
对了一下思路,然后发现还有一点问题。
首先显然对物品和背包按重量和容量从大到小排个序。
(考场这个地方写错了,为什么是从大到小是因为较大的背包的选择一定不会比小的背包劣。
然后就按物品价值的
搞一下。
这个地方用双指针来实现,一个指针指背包,另一个指物品,但是有一点要注意,就是当前背包个数小于求出来的值,要取个
,因为当前背包数量不足。
/*
事已至此,只能膜拜2017张晋杰大佬。
stO 张晋杰 Orz
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
const int C = 1000000000;
inline int min(int a,int b) { return a < b ? a : b; }
inline int max(int a,int b) { return a > b ? a : b; }
inline void read(int &x)
{
char ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';) ch = getchar();
for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar();
}
struct Things{ int val,w; } a[N];
struct SGT{ int ls,rs,val; } t[N * 10];
int n,m,T,b[N],ans,rt,tot;
bool cmp1(int a,int b) { return a > b; }
bool cmp(Things a,Things b) { return a.w > b.w || (a.w == b.w && a.val > b.val); }
int query(int p,int l,int r,int tl,int tr)
{
if(tl > tr) return 0;
if(l <= tl && tr <= r) return t[p].val;
int mid = tl + tr >> 1,ret = 0;
if(mid >= l) ret = query(t[p].ls,l,r,tl,mid);
if(mid < r) ret = max(ret,query(t[p].rs,l,r,mid + 1,tr));
return ret;
}
void change(int &p,int k,int x,int tl,int tr)
{
if(!p) p = ++tot, t[p] = (SGT){ 0,0,0 };
if(tl > tr) return;
if(tl == tr) { t[p].val = max(t[p].val,k); return; }
int mid = tl + tr >> 1;
x <= mid ? change(t[p].ls,k,x,tl,mid) : change(t[p].rs,k,x,mid + 1,tr);
t[p].val = max(t[t[p].ls].val,t[t[p].rs].val);
}
int main()
{
freopen("bag.in","r",stdin);
freopen("bag.out","w",stdout);
for(read(T);T--;ans = 0)
{
read(n);
for(int i = 1;i <= n; ++ i)
read(a[i].w), read(a[i].val);
read(m); sort(a + 1,a + 1 + n,cmp);
for(int i = 1;i <= m; ++ i) read(b[i]);
sort(b + 1,b + 1 + m,cmp1);
t[rt = tot = 1] = (SGT){ 0,0,0 };
for(int i = 1,j = 0,pos;i <= n; ++ i)
{
while(j < m && a[i].w <= b[j + 1]) ++j;
pos = min(j,query(rt,a[i].val,C,1,C) + 1), ans = max(ans,pos);
change(rt,pos,a[i].val,1,C);
}
printf("%d\n",ans);
}
fclose(stdin); fclose(stdout);
return 0;
}
考场太
傻了,竟然幻想着把
整一个求出来。
其实这也没有什么问题,但是自己的实现能力有限,写不出来,也因此付出了不少的时间。
事已至此,只能膜拜2017张晋杰大佬。
stO 张晋杰 Orz