当一个问题具有最优子结构性质时,可以使用动态规划法求解,但有时候使用贪心算法更简单,更直接而且解决问题的效率很高。 当一个问题具有最优子结构性质时,可以使用动态规划法求解,但有时候使用贪心算法更简单,更直接而且解决问题的效率很高。
贪心算法总是做出在当前看来最好的选择,也就是说贪心算法并不从整体最优考虑,它所做出的选择只是在某种意义上的局部最优选择,当然最终希望贪心算法得到的最终结果也是最优的。 例如前面动态规划算法中的硬币问题就可以用贪心算法来解决,从算法名字上来看,贪心算法总是做出在当前看来最好的选择,也就是说贪心算法并不从整体最优考虑,它所做出的选择只是在某种意义上的局部最优选择,当然最终希望贪心算法得到的最终结果也是最优的。
虽然贪心算法不能对所有问题都得到整体最优解,但是对于很多问题它能够产生整体最优解,或者是趋近于最优解。 虽然贪心算法不能对所有问题都得到整体最优解,但是对于很多问题它能够产生整体最优解,或者是趋近于最优解。
硬币问题
1,3,5分的硬币,现在给定一个价值c:11,问组成价值c需要的最少的硬币的数量???
int main()
{
int arr[] = { 5,3,1 };
int length = sizeof(arr) / sizeof(arr[0]);
int c = 11;
int idx = 0; // 5 3 1
int cnt = 0; // 记录硬币的个数
while (c > 0) {
if (c >= arr[idx]) {
c -= arr[idx];
cnt++;
}
else {
idx++;
}
}
cout << cnt << endl;
return 0;
}
部分背包问题
部分背包问题,有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过C的情况下让总价值尽量高。
每一个物体都可以只取走一部分,价值和重量按比例计算。求最大总价值。
struct Product {
double getPrice()const {
return v * 1.0 / w;
}
bool operator>(const Product &p) const {
return getPrice() > p.getPrice();
}
int id; // 物品的id
int w; // 物品的重量
int v; // 物品的价值
};
int main()
{
int w[] = { 8,6,4,2,5 };
int v[] = { 6,4,7,8,6 };
const int n = sizeof(w) / sizeof(w[0]);
int c = 12;
int x[n] = { 0 };
Product pros[n];
for (int i = 0; i < n; ++i) {
pros[i].id = i;
pros[i].w = w[i];
pros[i].v = v[i];
}
// 按物品的性价比降序排列
sort(pros, pros + n, [](const Product &p1, const Product &p2)->bool {return p1 > p2; });
// 按性价比高的往背包里面放(只考虑局部的最优解)
double bestv = 0.0; // 记录背包的最大价值
for (int i = 0; i < n; ++i) {
if (pros[i].w <= c) { // 说明第i个物品可以装入背包
bestv += pros[i].v;
c -= pros[i].w;
}
else { // 说明第i个物品无法全部装入背包,按剩余容量的比例装入物品的一部分
bestv = bestv + pros[i].v*(c*1.0 / pros[i].w);
x[pros[i].id] = 1;
break;
}
x[pros[i].id] = 1;
}
cout << "bestv:" << bestv << endl;
for (int v : x) {
cout << v << " ";
}
cout << endl;
return 0;
}
柜台提供服务
m个柜台提供服务,每个柜台给一个用户提供服务的时间是t(用数组表示每一个柜台提供服务的时间),
问怎么排列,使得柜台给所有用户提供服务的时间最少?
struct Counter { // 描述柜台
bool operator<(const Counter &counter) const {
return time < counter.time;
}
int id; // 柜台id
int time; // 柜台提供服务所花费的时间
};
int main()
{
int arr[] = { 3,2,4 }; // 每一个柜台提供服务的时间
const int m = sizeof(arr) / sizeof(arr[0]); // 柜台的数量
int n = 15; // 办理业务的人数
// 定义柜台信息数组,初始化柜台id和time
Counter cons[m];
for (int i = 0; i < m; ++i) {
cons[i].id = i;
cons[i].time = arr[i];
}
// 按照柜台提供服务的时间升序排列
sort(cons, cons + m);
int mintime = 0; // 记录给所有用户提供服务的最少时间
int x[m] = { 0 }; // 记录每一个柜台安排的用户数量
for (int i = 0; i < n; ++i) {
// 先计算把i用户放在0号柜台的时间
int time = cons[0].time * (x[0] + 1); // 1 5 5 1
// 再遍历其它的柜台,看是否可以得到更少的花费时间
int j = 1;
for (; j < m; ++j) {
int t = cons[j].time * (x[j] + 1);
if (t <= time) { // 放在其它柜台处理时间总体更快,直接放入j柜台
x[j]++;
// 新添加了一个人,整体花费的时间有可能变得更长了,更新mintime
if (t > mintime) {
mintime = t;
}
break;
}
}
// 最终还是放在0号柜台花费时间最少
if (j == m) {
x[0]++;
// 新添加了一个人,整体花费的时间有可能变得更长了,更新mintime
mintime = cons[0].time * x[0];
}
}
cout << mintime << endl;
for (int i = 0; i < m; ++i) {
cout << arr[cons[i].id] << " : " << x[i] << endl;
}
return 0;
}