贪心入门基础(装载问题,区间个数,haffman(优先队列))

贪心算法基础(超级基础的那种)

贪心法是一种解决问题的策略。如果正确,那么贪心法会易于描述和实现

装载问题

给出n个物体,每个物体体积为mi,单价为pi,有一个体积为m的背包,
问最多装多少价格最大。(假设物体可以分割)。
首先我们需要定义结构体和一个结构体数组,然后对单价进行递减的排序,每次都要选取单价最大的物体。

** 就像下面这个例题 **

话说上回讲到海东集团面临内外交困,公司的元老也只剩下XHD夫妇二人了。显然,作为多年拼搏的商人,XHD不会坐以待毙的。
一天,当他正在苦思冥想解困良策的时候,突然想到了自己的传家宝,那是公司成立的时候,父亲作为贺礼送来的一个锦囊,徐父当时交代,不到万不得已的时候,不要打开它。“现在不正是最需要的时候吗?”,一边想,XHD一边找到了这个精心保管的锦囊,打开一看,里面只有一句话“杭城北麓千人洞有宝”。
二话不说,XHD拿起一个大口袋就出发了,这个千人洞他是知道的,小的时候,爸爸曾经带他来过这个隐蔽的路口,并告诉他,这是千人洞。他现在才明白爸爸当初这句话的含义。
尽管有点印象,XHD还是花了很大的精力才找到这个异常隐蔽的洞口,走进一看,几乎惊呆了,真的是眼花缭乱!不过尽管宝贝的种类不少,但是每种宝贝的量并不多,当然,每种宝贝单位体积的价格也不一样,为了挽救HDU,现在请你帮忙尽快计算出来XHD最多能带回多少价值的宝贝?(假设宝贝可以分割,分割后的价值和对应的体积成正比)

Input
输入包含多个测试实例,每个实例的第一行是两个整数v和n(v,n<100),分别表示口袋的容量和宝贝的种类,接着的n行每行包含2个整数pi和mi(0<pi,mi<10),分别表示某种宝贝的单价和对应的体积,v为0的时候结束输入。

Output
对于每个测试实例,请输出XHD最多能取回多少价值的宝贝,每个实例的输出占一行。

Sample Input
2 2
3 1
2 3
0

Sample Output
5

#include<iostream>
#include<algorithm>
using namespace std;
struct node {//物品结构体
	int pi;
	int mi;
}arr[110];
bool cmp(node a, node b) {
	return a.pi > b.pi;
}
int main() {
	int v, n;
	while (cin >> v) {
		if (v == 0)break;//结束输入
		else {
			cin >> n;
			for (int i = 0; i < n; i++) {
				cin >> arr[i].pi >> arr[i].mi;
			}int sum = 0;
			sort(arr, arr + n, cmp);//保证下面每一步都是最优解
			for (int i = 0; i < n; i++) {
				if (v > arr[i].mi) {//可以完全装下目前的商品
					sum = sum + arr[i].mi*arr[i].pi;
					v = v - arr[i].mi;
				}
				else {//这个物品需要分割
					sum = sum + arr[i].pi*v;
					break;//已经装满
				}
			}
			cout << sum << endl;
		}
	}
	return 0;
}

题目链接

选择不相交区间

数轴上有n个开区间,起点ai,终点为bi,尽量选择多个区间,让选择的区间没公共点。

首先,假设有两个区间n和m,如果这两个区间,
n __________________
m _________
m完全在n的里面 这个时候明显选择m是最好的选择,因为不仅可以选择一个区间,而且还可以省下n-m的空闲区间。

a 1___
… b____________
…c___________
这个时候
如果区间a和区间b没有相交,那么选择区间a是明智的,如果区间a和区间b相交了,那么选择区间a仍然是明智的。
因为在区间a中1之前的部分是没有影响的,对于后续选择有影响的只是大于1的部分,而这个有影响的部分明显小于b。因此,选择a。

例题
今年暑假不AC HDU - 2037
“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%…”

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
Input
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
Output
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
Sample Input
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
Sample Output
5
题目链接

#include<iostream>
#include<algorithm>
using namespace std;
struct node{//节目
	int sx, ex;
}arr[110];
bool cmp(node a, node b) {
	return a.ex < b.ex;
}
int main() {
	int n;
	while (cin >> n) {
		if (n == 0)break;
		else {
			for (int i = 0; i < n; i++) {
				cin >> arr[i].sx >> arr[i].ex;
			}sort(arr, arr + n, cmp);//对结束时间进行排序
			int count = 1;//需要输出的答案
			int cur = arr[0].ex;//用来连接
			for (int j = 1; j < n; j++) {//第j个可不可以选择
				if (arr[j].sx >= cur) {//第j个可以选择
					cur = arr[j].ex;//更新
					count++;
				}
			}cout << count << endl;
		}
	}
	return 0;
}

Huffman编码

问题描述
  Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
  给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。
  在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
  本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。

例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
输入格式
  输入的第一行包含一个正整数n(n<=100)。
  接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
  输出用这些数构造Huffman树的总费用。
样例输入
5
5 3 8 2 9
样例输出
59

#include<iostream>
#include<queue>
using namespace std;
int main() {
	priority_queue<int, vector<int>, greater<int > >q;//定义一个优先队列
	int n, s;
	cin >> n;
	while (n--) {
		cin >> s;
		q.push(s);
	}
	int a, b;
	int ans = 0;
	while(q.size()!=1){
		a = q.top();
		q.pop();
		b = q.top();
		q.pop();
		q.push(a + b);
		ans += a + b;
	}
	cout << ans<< endl;
	return 0;
}

…结束了…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值