洛谷-运输(P2094)

题目链接:

运输问题

问题分析:

初读题目,可能有点搞不懂。题目要求:二当一(两件的价格算一件),并且给出了这个价格是如何计算的。题目的关键点在:如此反复。直到只收一件商品的钱。 分析到这,是否感觉有点类似哈夫曼编码以及洛谷中的另一道贪心习题-合并果子?
按照这个思路,写出如下的代码:

#include<iostream>
#include<algorithm>
using namespace std;

bool cmp(int a, int b){
 return b < a;
}

int main(){
 	int n, k;
 	cin >> n >> k;
 	int ars[n];
 	for(int i = 0; i < n; i++)
 		cin >> ars[i]; 
 	sort(ars, ars+n, cmp);
 	for(int i = 0, j; i < n-1; i++){//如题解,每次选取最大两个值进行运算(合并果子?) 
  		ars[i+1] = (ars[i] + ars[i+1]) / k; 
  		int t = ars[i+1];
  		for(j = i+2; j < n && t < ars[j]; j++){//为新值找合适位置 
  	 		ars[j-1] = ars[j];//向前移动 
  		}
  		ars[j-1] = t;
 	}
 	cout << ars[n-1];
 	return 0;
}

提交后发现,思路正确。但是不禁有两个疑问:a.为什么采取上述策略可以有效解决问题呢?b.上述代码的时间复杂度显然是O(n^2),耗时的操作主要浪费在为新值寻找合适位置上了。是否存在有效的解决方案降低时间复杂度呢?看了很多博文,大佬们用的都是优先队列,不妨通过此类题目学习一下优先级队列。按照上述两个疑问,本篇博文一下将分别分析。

疑问A分析:

题目要求运费最少,则最优解为运费最少的情况。分析运费的计算情况,如何让运费最少?我们不妨将上述新运费计算方式当作一种打折活动,买东西时,我们自然希望贵重的物品的折扣越大越好,或者打的折扣次数尽量多。回到本题,若每次最贵重的物品参与的/k次数越多,最终的费用也不久最少吗?相比选择便宜的物品,打相同次数的折扣自然要比贵重物品少很多。因此问题不难得证。

优先级队列:

其使用方法同普通队列没有什么区别,先看下其一般使用方法:

#include<bits/stdc++.h> 
using namespace std;

int main(){
 	priority_queue<int>que;
 	queue<int> q;
 	for(int i = 0; i < 10; i++){
  		int t = rand() % 10;
  		q.push(t);
  		que.push(t);
 	}
 	cout << "priority_queue:" << endl;  
 	for(int i = 0; i < 10; i++){
 		cout << que.top() << " ";
  		que.pop();
 	}
 	cout << "\nqueue:" << endl;
 	for(int i = 0; i < 10; i++){
  		cout << q.front() << " ";
  		q.pop();
 	}
 	return 0;
}

通队列基本没有什么区别,不同的是,其是按序排列的。通过上述实践,也可以发现:优先级队列默认按最大值优先的顺序。
倘若我们想改变优先级顺序,该如何实现?c++提供了自带的库函数,当然我们也可以自定义。先看下自带的库函数操作:

#include<bits/stdc++.h>
using namespace std;

int main(){
 	priority_queue<int, vector<int>, greater<int> > que_greater;
 	priority_queue<int, vector<int>, less<int> > que_less;//默认效果 
 	priority_queue<int, vector<int>, equal_to<int> > que_equal_to;
	priority_queue<int, vector<int>, greater_equal<int> > que_greater_equal;
 	priority_queue<int, vector<int>, less_equal<int> > que_less_equal;
 	for(int i = 0; i < 10; i++){
  		int t = rand() % 10;
  		que_greater.push(t);
  		que_less.push(t);
  		que_equal_to.push(t);
  		que_greater_equal.push(t);
  		que_less_equal.push(t);
 	}
 	cout << "greater:" << endl;
 	for(int i = 0; i < 10; i++){
  		cout << que_greater.top() << " ";
  		que_greater.pop();
 	}
 	cout << "\nque_greater_equal:" << endl;
 	for(int i = 0; i < 10; i++){
  		cout << que_greater_equal.top() << " ";
  		que_greater_equal.pop();
 	}
 	return 0;
}

自定义比较操作:

#include<bits/stdc++.h>
using namespace std;

struct cmp1{
 	bool operator()(int &a, int &b){
 	 	return a < b;
 	}
};
struct cmp2{
 	bool operator()(int &a, int &b){
  		return a > b;
 	}
};

int main(){
 	priority_queue<int, vector<int>, cmp1> que_cmp1;
 	priority_queue<int, vector<int>, cmp2> que_cmp2;
 	for(int i = 0; i < 10; i++){
  		int t = rand() % 10;
  		que_cmp1.push(t);
  		que_cmp2.push(t);
 	}
 	cout << "cmp1:\n";
 	for(int i = 0; i < 10; i++){
  		cout << que_cmp1.top() << " ";
  		que_cmp1.pop();
 	}
 	cout << "\ncmp2:\n";
 	for(int i = 0; i < 10; i++){
  		cout << que_cmp2.top() << " ";
  		que_cmp2.pop();
 	}
 	return 0;
}

将上述题目用优先级队列重写一下:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

int main(){
 	int n, k;
 	cin >> n >> k;
 	priority_queue<int>que;
 	for(int i = 0; i < n; i++){
  		int t;
  		cin >> t;
  		que.push(t);
 	}
 	for(int i = 0, j; i < n-1; i++){
  		int x, y, z;
  		x = que.top();
  		que.pop();
  		y = que.top();
  		que.pop();
  		z = (x+y) / k;
  		que.push(z);
 	}
 	cout << que.top();
 	return 0;
}

关于优先级队列更多细节可移步大佬博客:
优先级队列(上)
优先级队列(下)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值