贪心策略(活动选择问题)

活动选择问题

考虑收益的会场出租问题

 无法采用贪心策略,选择动态规划法解决

 

贪心策略解决哈夫曼编码

#include<iostream>
#include<vector>

using namespace std;

struct E
{
	char w;
	int weight;

	E()
	{
		w = NULL;
		weight = -1;
	}
	E(char e, int r)
	{
		w = e;
		weight = r;
	}	
};

struct node
{
	E data=E();
	node* parent=NULL;
	node* left=NULL;
	node* right=NULL;

	bool whether = false;//是否为真节点

	node(E a)
	{
		data = a;
		whether = true;
	}

	node(E a,node* p,node* l,node *r)
	{
		data = a;
		parent = p;
		left = l;
		right = r;;
		whether = true;
	}

	node(node* l, node* r)//构建虚假节点
	{
		data.weight = l->data.weight + r->data.weight;

		left = l;
		right = r;

		l->parent = this;
		r->parent = this;
	}

	bool operator ==(node a)
	{
		if (this->data.weight == a.data.weight)
			return true;
		else
			return false;
	}
	void operator =(node a)
	{
		data = a.data;
		parent = a.parent;
		left = a.left;
		right = a.right;
	}
};

int compare(const void * A, const void *B)
{
	E* a = (E*) A;
	E* b = (E*) B;

	if ( a->weight < b->weight)
		return false;
	else
		return true;
}

vector<node> tree;//如果放在函数,函数结束会清除数据。。。

void set(E* data, int length)
{
	int index = 0;


	qsort(data, length, sizeof(E), compare);//从小到大排序,越大权重越高,则越在上面

	

	while (index++ != length-1)
	{
		E a = data[1];//大的在做小的在右
		E b = data[0];

		node* A =new node(a);
		node* B =new node(b);
		if (a.w == NULL)//如果为虚假E,代表为合成节点,则必存在相应合成节点在树中暂存
		{
			vector<node>::iterator iter=std::find(tree.begin(),tree.end(),*A);//找到树中目标
			int where= std::distance(tree.begin(), iter);//找到下标值
			*A = tree[where];//得到该节点的值
			tree.erase(iter);//删去该节点
		}
				
		if (b.w == NULL)
		{
			vector<node>::iterator iter = std::find(tree.begin(), tree.end(), *B);
			int where = std::distance(tree.begin(), iter);
			*B = tree[where];
			tree.erase(iter);
		}
			

		node *C = new node(A, B);//虚假节点,自动形成联系

		tree.push_back(*C);

		int num = a.weight + b.weight;
		data[0].weight = num;
		data[0].w = NULL;
		data[1].weight = 9999;
		qsort(data, length, sizeof(E), compare);
	}
}

void encoding(node* head, string encode = "")
{
	if (head->left)
		encoding(head->left, encode + '0');
	else
	{
		cout << head->data.w << ":" << encode << "   " << head->data.weight << endl;
		return;
	}

	if (head->right)
		encoding(head->right, encode + '1');
	else
		cout << head->data.w << ":" << encode << "   " << head->data.weight << endl;

}

int main()
{
	E e[5]{ E('a',5),E('b',3),E('c',7),E('d',8),E('e',1) };
	set(e, 5);

	encoding(&tree[0],"");

	return 0;
}

 贪心策略解决活动选择

#include<iostream>
#include<algorithm>
#include <vector>
using namespace std;
bool cmp(const pair<int,int>& a, const pair<int,int>& b)
{
    return a.second < b.second;
}
int greedyActivitySelector(const vector<pair<int,int>>& act)
{
//贪婪策略:每次选择最早结束的活动
//num是统计举办的活动个数
    int num = 1, i = 0;
    for (int j = 1; j < act.size(); j++)
    {
        //后一个活动的开始时间小于前一个活动的结束时间
        if (act[j].first >= act[i].second)
        {
            i = j;
            num++;
        }
    }
    return num;
}
int main()
{
    int number;
    cin >> number;
    vector<pair<int, int>> act(number);
    int idx = 0;
    for (int i = 0; i < act.size(); ++i)
    {
        cin >> act[i].first >> act[i].second;
    } //按照活动截止时间从小到大排序
    sort(act.begin(), act.end(), cmp);
    int ret = greedyActivitySelector(act);
    cout << ret << endl;
    
    return 0;
	 
}

 动态规划解决贪心策略

#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define maxn 105

//记录每个活动的开始和结束时间 
struct Edge {
	int begin;//开始时间 
	int end;//结束时间 
	int value;//价值 
};

bool cmp(Edge a, Edge b) {
	return a.end < b.end;
}

int find(int target, int left, int right);
void print();

//p[i]记录在a[i]开始前最后结束的活动
//D[i]表示{a1,a2```ai}中不冲突最大权重之和
//Rec[i]记录决策过程,1表示选择活动a[i],0表示不选活动a[i] 
int p[maxn], D[maxn], Rec[maxn];
Edge edge[maxn];
int n;

int main() {
	cin >> n;//输入n个备选活动
	//分别输入每个活动的起始时间和结束时间 
	for (int i = 1; i <= n; i++) {
		cin >> edge[i].begin >> edge[i].end >> edge[i].value;
	}
	//按照结束时间升序排序
	sort(edge + 1, edge + n + 1, cmp);
	//二分求解p[i] 
	for (int i = 1; i <= n; i++) {
		p[i] = find(edge[i].begin, 1, n);
	}
	memset(D, 0, sizeof(D));
	memset(Rec, 0, sizeof(Rec));
	for (int i = 1; i <= n; i++) {
		//选择活动ai 
		if (D[p[i]] + edge[i].value > D[i - 1]) {
			D[i] = D[p[i]] + edge[i].value;
			Rec[i] = 1;
		}
		else {//不选活动ai 
			D[i] = D[i - 1];
			Rec[i] = 0;
		}
	}
//	for (int i = 1; i <= n; i++) {
//		cout << p[i] << " ";
//	}
//	cout << endl;
//	for (int i = 1; i <= n; i++) {
//		cout << D[i] << " ";
//	}
//	cout << endl;
//	for (int i = 1; i <= n; i++) {
//		cout << Rec[i] << " ";
//	}
	print();
	return 0;
}

//二分查找 
int find(int target, int left, int right) {
	if (target < edge[left].end) return 0;
	int mid = (left + right) / 2;
	if (edge[mid].end == target || (edge[mid].end<target && edge[mid + 1].end>target)) {
		return mid;
	}
	else if (target > edge[mid].end) {
		return find(target, mid + 1, right);
	}
	else {
		return find(target, left, mid);
	}
}

void print() {
	int k = n;
	while (k > 0) {
		if (Rec[k] == 1) {
			cout << "选择第" << k << "个活动 begin:" << edge[k].begin << " end:" << edge[k].end << " value:" << edge[k].value << endl;
			k = p[k];//找第k个的前一个可选项目 
		}
		else {
			k--;
		}
	}
	cout << "最大价值为:" << D[n] << endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值