20行代码AC_ 习题8-1 Bin Packing UVA - 1149(贪心+简单二分解析)

励志用少的代码做高效表达


题意

给定N个物品的中联L1,背包的容量M,同时要求每个背包最多装两个物品,求至少要多少个背包才能装下所有的物品。

解题过程

第一次接触背包类问题。

最初的思路是降序排序,i从最大值遍历,j从i后遍历,直到找到可以装在一个背包里的两个物体,若无,则把最大值单独装包。时间复杂度为O(n^2),超时且复杂。

网搜后,发现更优化的思路是:升序排序,从i最小的值遍历,j从最大的值遍历,若二者和满足条件,则装包, 反之将较大值单独装包。

于是我陷入了思考, 为什么只是将排序调整一下,时间复杂度和代码复杂度大不相同呢

经过脑暴,我得到了以下结论:
如果降序排序,每遍历一次,不符合条件者会被跳过,进而参与一次又一次的循环判断;
而升序排序后,每遍历一次,无论是否符合条件,都会被处理,因此效率大大提高(简单二分的原理,分而治之)。
也正因后者每次遍历都会做相应的处理,因此每次判断都会控制在数列的两端,思路就会简单很多。

可见,一道题的AC与否往往在一念之间,如果灵活一些思考,或许会更快更好的解决问题

下面贴代码。

需要注意的是,虽然N<=10^5, 但数组设为a[100005]会爆掉。 最后改成了a[100010],成功AC。也算是一个小技巧

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main() {
    
    
	ios::sync_with_stdio(false);
	int T; cin>>T; while(T--) {
    
    
		int n, num;  cin>>n>>num;
		for(int i = 0; i < n; i++) cin>>a[i];
		sort(a, a+n);
		
		int i = 0, j = n-1, sum = 0;
		while(i <= j)  {
    
    
			if(i == j) {
    
     sum++; break; } 
			
			if(a[i]+a[j] <= num) {
    
     i++; j--; sum++; } 
			else {
    
     j--; sum++; }
		}
		cout << sum << endl << (T?"\n":"");
	} 
return 0; } 

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/108294389
今日推荐