活动选择问题
考虑收益的会场出租问题
无法采用贪心策略,选择动态规划法解决
贪心策略解决哈夫曼编码
#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;
}