算法-贪心

例12-1:(洛谷P2240)部分背包问题:

#include <iostream>
#include <cstdio>
using namespace std;
int m[110], v[110];
double p[110];
double price(int n,int t) {
	if (n == 0) {
		return 0;
	}
	if (t - m[n] > 0) {
		return price(n - 1, t-m[n]) + v[n];
	}
	else {
		return v[n] * 1.0*t/m[n];
	}
}
int main() {
	int n, t;
	cin >> n >> t;
	for(int i=1;i<=n;i++){
		cin >> m[i] >> v[i];
		p[i] = 1.0*v[i] / m[i];
	}
	for (int i = 1; i < n; i++) {
		for (int j = i + 1; j <= n; j++) {
			if (p[i] > p[j]) {
				double m0 = p[i];
				p[i] = p[j];
				p[j] = m0;
				double m1 = m[i];
				m[i] = m[j];
				m[j] = m1;
				double m2 = v[i];
				v[i] = v[j];
				v[j] = m2;
			}
		}
	}
	printf("%.2f", price(n, t));
	return 0;
}

 证明贪心的第一中方法--假设要选择的方案不是贪心算法所要求的方案,只需要证明将需要贪心的方案替换掉要选择方案,结果会更好(至少不会更差)。

使用贪心策略要特别注意其正确性。

例12-2:(洛谷P1223)排队接水

#include <iostream>
#include <cstdio>
using namespace std;
#include <algorithm>
typedef struct person {
	int id;
	int time;
}Student;
Student student[1100];
int time1[1100];
bool cmp(Student a,Student b) {
	return a.time < b.time;
}
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> student[i].time;
		student[i].id = i;
	}
	sort(student + 1, student + n + 1,cmp);
	for (int i = 1; i <= n; i++) {
		cout << student[i].id<<' ';
	}
	cout << endl;
	double average=0;
	for (int i = 1; i <= n; i++) {
		time1[i]=student[i].time;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = i - 1; j > 0; j--) {
			time1[i] += student[j].time;
		}
		time1[i] -=student[i].time;
		average += time1[i];
	}
	average=1.0*average/n;
	printf("%.2f", average);
	return 0;
}

例12-3:(洛谷P1803)凌乱的yyy:

#include <iostream>
using namespace std;
#include <algorithm>
struct game {
	int beginning;
	int ending;
}g[1000001];
bool cmp(struct game a,struct game b) {
	if (a.ending != b.ending) return a.ending < b.ending;
}
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> g[i].beginning >> g[i].ending;
	}
	sort(g + 1, g + n + 1,cmp);
	int sum=0;
	int flag = 0;
	for (int i = 1; i <= n; i++) {
		if (flag <= g[i].beginning) {
			sum++;
			flag = g[i].ending;
		}
	}
	cout << sum;
	return 0;
}

证明贪心的另一种方法:数学归纳法,每一步的选择都是到当前为止的最优解,一直到最后一步就成为了全局的最优解。

如果两个时间冲突,

(1)一个比赛被另一个比赛包含,选先结束的那个。

(2)两个比赛相交,选先结束的那个。

应该选择参加最先结束的那场比赛,接下来要选择能够参加的比赛(所有和上一场冲突的比赛都不能够参加了)中,最早结束的比赛,直到没有比赛可以参加为止。

哈夫曼编码:

例12-4:分卷子

例12-5:合并果子:

#include <iostream>
using namespace std;
#include <algorithm>
#include <cstring>
long long a[10010];
long long b[10010];
int main() {
	int n;
	cin >> n;
	memset(a, 127, sizeof(a));
	memset(b, 127, sizeof(b));
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a + 1, a + n + 1);
	int x, i = 1, j = 1, n1 = 0, sum=0;
	for (int w = 1; w < n; w++) {
		x = a[i] < b[j] ? a[i++] : b[j++];//取第一个最小值
		x+= a[i] < b[j] ? a[i++] : b[j++];//取第二个最小值
		b[++n1] = x;
		sum += x;
	}
	cout << sum;
	return 0;
}

使用memset初始化int数组:

第二个参数如果是0,数组就会被初始化为0;

如果是127,会初始化为一个很大且很接近int类型上限的正数;

如果是128,会初始化成很小且接近int类型下限的负数;

如果是-1或者255,时,数组会初始化为-1.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值