活动选择问题(贪心)

假设有n个活动,每个活动有一个起始时间和一个结束时间,现在想在一段固定时间内安排最多的活动数。这个问题是典型的贪心问题,我们把所有的活动按结束时间从小到大排序,这样可以知道最小的那个活动a1一定在最优集合里,因为假设最优结构中没有a1,而是它的最小活动为另一个数假设ax,因为a1是所有活动中最小的,所以如果我们把ax换成a1,最优集合里所有的活动还是兼容的,所以a1一定在最优集合中。这样我们只要先选出a1,然后再对除去a1后所有起始时间大于等于a1结束时间的活动进行贪心即可,每次选择当前集合中结束时间最小的活动就可以得到最大的活动数。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node
{
	int s, f;
};
vector<int> time;

bool cmp(const node a, const node b)
{
	return a.f<b.f;
}

int main()
{
	int n;
	cout << "Enter all intervals of time can be chosen" << endl;
	cin >> n;
	node *p = new node[n+1];
	cout << "Enter the start and end of time intervals" << endl;
	for (int i = 1; i <= n; i++)
		cin >> p[i].s >> p[i].f;
	sort(p+1, p + n + 1, cmp);//先按照结束时间从小到大排序
	int k = 1;
	time.push_back(1);
	for (int m = 2; m <= n; m++)
	{
		if (p[m].s >= p[k].f)//找到最小的比上一个结束时间大的开始时间,就选它作为下一个时间段
		{
			time.push_back(m);
			k = m;
		}
	}
	cout << "There are most "<<time.size()<<": ";
	int temp = time.size();
	for (int i = 0; i < temp; i++)//倒序输出
	{
		cout << time.back() << "  ";
		time.pop_back();
	}
	cout << endl;
	delete[] p;
	return 0;
}


活动选择问题旨在找到一个最大的相容活动子集,贪心算法的思路是优先选择结束时间早的活动,因为结束时间早的活动留下的空闲时间多,能给其他活动提供更多机会。 以下是使用 C++ 实现贪心算法解决活动选择问题的代码: ```cpp #include<iostream> using namespace std; // 对活动按照结束时间进行排序 void sort(int n, int s[], int f[]) { int a, b, i, j; for (i = 1; i <= n; i++) { for (j = i + 1; j <= n; j++) { if (f[i] > f[j]) { a = f[i]; f[i] = f[j]; f[j] = a; b = s[i]; s[i] = s[j]; s[j] = b; } } } } // 贪心选择函数,返回最大相容活动子集的活动数量 int GreedySelect(int n, int s[], int f[], bool A[]) { A[1] = true; int j = 1, count = 1; for (int i = 2; i <= n; i++) { if (s[i] >= f[j]) { A[i] = 1; j = i; count++; } else A[i] = 0; } return count; } int main() { int n, s[50], f[50]; bool A[50]; cin >> n; for (int i = 1; i <= n; i++) { cin >> s[i] >> f[i]; } sort(n, s, f); cout << GreedySelect(n, s, f, A) << endl; return 0; } ``` 上述代码首先定义了排序函数 `sort` 对活动按照结束时间进行排序,接着 `GreedySelect` 函数实现贪心选择过程,在遍历活动时,若当前活动与已选活动集合中的最后一个活动时间不冲突,则将其加入集合。在 `main` 函数中,读取活动开始时间结束时间,调用排序函数,再调用贪心选择函数,并输出最大相容活动子集的活动数量 [^1]。 还有另一种实现方式: ```cpp #include <iostream> using namespace std; int main() { int n; int a[101]; // 开始时间 int b[101]; // 结束时间 int c[101]; // 活动序号 cin >> n; int da, db, dc; for (int i = 0; i < n; i++) { cin >> a[i] >> b[i]; c[i] = i + 1; } for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) { if ((b[j] < b[i]) || (b[j] == b[i] && a[i] > a[j])) { da = a[i]; a[i] = a[j]; a[j] = da; db = b[i]; b[i] = b[j]; b[j] = db; dc = c[i]; c[i] = c[j]; c[j] = dc; } } int z[101]; // 标记最佳安排的活动 int t = 0; int s = 0; for (int i = 0; i < n; i++) { if (i == 0) { z[t] = c[i]; t++; s = i; } else if (a[i] >= b[s]) { z[t] = c[i]; t++; s = i; } } for (int i = 0; i < t; i++) { if (i == t - 1) cout << z[i] << endl; else cout << z[i] << ","; } return 0; } ``` 这段代码同样解决活动选择问题,在 `main` 函数中完成活动的输入、排序、贪心选择过程,最后输出最大相容活动子集的活动序号 [^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值