贪心算法算是比较简单的算法,他需要包含两种性质,一种是贪心选择性质,另外一种是最优子结构性质。
百度上的定义
在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择
解题角度
对于初学者而言,我觉得题目可以从以下角度入手:
- 是否能给输入按照一定标准排序
- 后面的解决办法是否跟前面有关即为,( d i s t a n c e [ i + 1 ] = d i s t a n c e [ i ] distance[i+1]=distance[i] distance[i+1]=distance[i])
- 求解顺序是否是从前往后,或者具有一定顺序。
7-1 汽车加油问题
题目来源:王晓东《算法设计与分析》
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。
输入格式:
第一行有 2 个正整数n和 k(k<=1000 ),
表示汽车加满油后可行驶n公里,且旅途中有 k个加油站。
第二行有 k+1 个整数,表示第 k 个加油站与第k-1 个加油站之间的距离。
为什么会有k+1个数字呢?
ans:因为从起始站开始到终点共有n+1条线段
第 0 个加油站表示出发地,汽车已加满油。
第 k+1 个加油站表示目的地。
输出格式:
输出最少加油次数。如果无法到达目的地,则输出“No Solution!”。
所以他有两种输出方式
输入样例:
7 7
1 2 3 4 5 1 6 6
输出样例:
4
完整代码如下
#include<bits/stdc++.h>
using namespace std;
#define MAXSIZE 1010
int dist[MAXSIZE] = { 0 };
int main() {
int numIn = 0;
int maxWalk = 0;
int timesPickUp = 0;
cin >> maxWalk >> numIn;
int tem = maxWalk;
//在起点的时候加满油了,这里初值一定要赋予。
for (int i = 0; i <= numIn; i++) {
cin >> dist[i];
}
for (int i = 0; i < numIn; i++) {
tem -= dist[i];
if (tem <= dist[i + 1] && tem + maxWalk >= dist[i + 1]) {
//cout << i << " " << dist[i + 1] << " " << tem << endl;
tem += maxWalk;
timesPickUp++;
}
else if (tem + maxWalk < dist[i + 1]) {
cout << "No Solution!";
return 0;
}
else {
if (tem < 0) {
cout << "No Solution!";
return 0;
}
}
}
//cout << endl;
cout << timesPickUp;
return 0;
}
贪心策略
这里的话,我主要考虑的是选取当我在i站的时候,考虑我能不能走到下一站,即为考虑i+1到i站的距离,所以这里会出现如下逻辑判断表达式
if (tem <= dist[i + 1] && tem + maxWalk >= dist[i + 1]) {
//判断是否能够到达下一站,tem是剩余的油量能走的公里数,
//maxWalk为加满油之后能走的公里数
//而且这种情况是是在i站的时候发现剩余不够,
//然后在i站加油之后能够顺利到达i+1站
tem += maxWalk;
timesPickUp++;
}
else if (tem + maxWalk < dist[i + 1]) {
//而且这种情况是是在i站的时候发现剩余不够,
//然后在i站加油之后能够不能顺利到达i+1站
cout << "No Solution!";
return 0;
}
else {
if (tem < 0) {
//剩余油量不能到达
cout << "No Solution!";
return 0;
}
容易错误的点
赋初值
int tem = maxWalk;
//在起点的时候加满油了,这里初值一定要赋予。