每一步都是局部最优,但是不一定是整体最优,一般是近似解
1.找零问题 成立
2.石子合并问题 部分不成立
一、找零问题:
25/10/5/1 这四种币额去凑出48美元,使给出的硬币数量最少
第一步,可以给出4种面额中的任何硬币,贪心算法会选择一个25的硬币,因为它能把余下的数量降到最低,剩余23美分;
第二步,最佳选择是10美元硬币,能把余下的数量降到最低,剩余13美分;
第四步,同理,选择10美元硬币,剩余3美分;
第五步:没得选了,三个1美元硬币;
举例:
设有50、20、10、5、1、0.5、0.1等面额的零钱,顾客购物花费n元,在支付(int)(n / 100 + 1) * 100元后,收银员应如何找零,才能使找回的钱数最少
输入:n,表示顾客所花的钱数,最多包含一位小数。
输出:找回的零钱数。
样例输入1:67.5
样例输出1:5
样例输入2:243
样例输出2:4
代码一:方便理解,思路清晰明了
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
double realspend;
(void)scanf("%lf", &realspend);
int spend = realspend * 10;
int leave = ((int)(spend / 1000) + 1) * 1000 - spend;
int i = 0;
while (leave >= 500)
{
leave = leave - 500;
i++;
}
while (leave >= 200 && leave < 500)
{
leave = leave - 200;
i++;
}
while (leave >= 100 && leave < 200)
{
leave = leave - 100;
i++;
}
while (leave >= 50 && leave < 100)
{
leave = leave - 50;
i++;
}
while (leave >= 10 && leave < 50)
{
leave = leave - 10;
i++;
}
while (leave >= 5 && leave < 10)
{
leave = leave - 5;
i++;
}
while (leave >= 1 && leave < 5)
{
leave = leave - 1;
i++;
}
printf("%d", i);
return 0;
}
代码二:“炫技代码”,华而不实
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
using namespace std;
int TanxinZhaoLing(int leave, int* yingbi)
{
int zhangshu=0;
for (int i = 0; leave != 0; i++)
{
if (leave < yingbi[i])
continue;
leave = leave - yingbi[i];
zhangshu++;
i--;
}
return zhangshu;
}
int main()
{
double spend;
(void)scanf("%lf", &spend);
spend = spend * 10;
int a[7] = {500,200,100,50,10,5,1};
int leave = ((int)(spend / 1000) + 1) * 1000 - spend;
int zhangshu = TanxinZhaoLing(leave, a);
printf("%d", zhangshu);
return 0;
}
二、活动安排问题
有n个活动,E={1,2,3...},其中每个活动都要求使用同一资源,同一时间内只有一个活动能使用这一资源,每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi。如果选择了活动i,则它在半开区间(si,fi)内占用资源,如果(si,fi)和(sj,fj)区间不相交,则称活动i和活动j是相容的,也就是说,si>=fj,或sj>=fi时,活动i和活动j相容。活动安排问题就是要在所给的集合中选出最大的相容活动子集合。
求解思路:尽量选择结束时间早的活动:将活动按照结束时间大小进行排序,然后用i代表第i个活动,s[i]代表第i个活动开始时间,f[i]代表第i个活动结束时间
布尔型(bool)变量的值只有 真 (true) 和假 (false)
布尔型运算结果常用于条件语句
#include<stdio.h>
#include<iostream>
using namespace std;
//选择函数,输入项目个数,开始时间,结束时间,布尔类型的值
void GreedyChoose(int len, int* startTime, int* endTime, bool* mark)
{
mark[0] = true; //第一个活动一定安排
int j = 0;
for (int i = 1; i < len; i++)
{
if (startTime[i] >= endTime[j]) //从第二个项目开始找开始时间大于前一个结束时间的活动
{
mark[i] = true; //布尔类型,满足条件就true
j = i; //更改成最后一个安排的活动
}
}
}
int main()
{
int startTime[11] = {1,2,0,5,3,5,6,8,8,2,12}; //开始的时间
int endTime[11] = { 4,5,6,7,8,9,10,11,12,13,14 }; //结束的时间
bool mark[11] = {false};
//如果选择某个活动,则数组mark对应位置为true,否则为false
GreedyChoose(11, startTime, endTime, mark);
cout << "NO.\t" << "sTime\t" << "eTime\t" << endl;
for (int i = 0; i < 11; i++)
{
if (mark[i])
{
cout << i + 1 << "\t" << startTime[i] << "\t" << endTime[i] << endl;
} //输出结果
}
return 0;
}
三、马踏棋盘算法
基本解法:深度优先搜索
从某位置出发,先试探下一个可能位置;进入一个新位置后就从该位置进一步试探下一个位置,若遇到不可行位置则退回一步;再试探其他位置
8*8数组chess[][]存储棋子周游状态,未走过位置赋值0,走过的位置依次为1,2,3,4
(x,y)为当前位置,j为当前第几步
辅助算法:贪心算法
在选择下一跳的位置时,总是先选择出口少的那个位置:
如果优先选择出口多的子结点,那么出口少的子结点会越来越多,很可能出现走不通的死结点,回退搜索浪费时间
四、数字组合问题:设有N个正整数,需要设计一个程序,使他们链接在一起成为最大的数字
冒泡排序
每次循环都会把最大的移动到最后面
for (int i = 0; i < 9; i++) //外循环表示循环多少次(n个数:n-1)
{
for (int j = 0; j <= 10- 1 - i; j++) //内循环表示比较的数据
{ //10-1是下标
if (array[j] > array[j + 1])
{
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}