JZOJ6413【NOIP2019模拟11.07】背包问题(bag)

背包问题(bag)

题目描述:
在这里插入图片描述

输入:
从文件 bag.in 中读入数据。
单个测试点中包含多组数据,输入第一行为一个非负整数 T,描述数据组数。接下来依次描述每组数据,对于每组数据:
第一行一个非负整数 n,描述物品数量。
第 2 行至第 n + 1 行,每行两个用空格隔开的正整数,其中第 i + 1 行的两个数依次为 wi, vi,分别描述第 i 个物品的重量和价值。
接下来一行一个非负整数 m,描述背包数量。
接下来一行 m 个用空格隔开的正整数 t1, . . . , tm,依次描述各背包的承重上限。

输出:
输出到文件 bag.out 中。
一行一个整数,表示能够选出的物品数量的最大值。

这道题考场想到了,但是写挂了。
然后跟 Z J J ZJJ 对了一下思路,然后发现还有一点问题。

首先显然对物品和背包按重量和容量从大到小排个序。
(考场这个地方写错了,为什么是从大到小是因为较大的背包的选择一定不会比小的背包劣。

然后就按物品价值的 L I S LIS 搞一下。
这个地方用双指针来实现,一个指针指背包,另一个指物品,但是有一点要注意,就是当前背包个数小于求出来的值,要取个 m i n min ,因为当前背包数量不足。

/*
	事已至此,只能膜拜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;	
} 

考场太 T M ^{TM} 傻了,竟然幻想着把 L I S LIS 整一个求出来。
其实这也没有什么问题,但是自己的实现能力有限,写不出来,也因此付出了不少的时间。

事已至此,只能膜拜2017张晋杰大佬。
stO 张晋杰 Orz

猜你喜欢

转载自blog.csdn.net/INnovate2030/article/details/102953268