贪心算法(又称贪婪算法)
是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。
第一个问题 找零
假设商店老板需要找零n元钱,钱币的面额有:100元、50元、20元、5元、1元,如何找零使得所需钱币的数量最少?
public void ChangeMoney(int n)
{
Debug.Log("一共要找的钱:"+n);
int[] money = new int[] { 100, 50, 20, 5, 1 };//面值
int[] change = new int[] { 0, 0, 0, 0, 0 };//计数
for (int i = 0; i < money.Length; i++)
{
//for example
//345 /100=3 345%100=45
//45 /50=0 45%50=45
//45 /20=2 45%20=5
//5/5=1 5&5=0;
//3 0 2 1 0
if (n == 0) break;
change[i] = n / money[i];
n=n % money[i];
}
PrintArry(change,"");
}
测试一下345
没问题
第二个问题 分数背包
一个小偷在某个商店发现有n个商品,第i个商品价值vi元,重wi千克。他希望拿走的价值尽量高,但他的背包最多只能容纳W千克的东西。他应该拿走哪些商品?(每种商品只有一个)
0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分(商品为金条)
分数背包:对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)
举个栗子
商品1:V1=60 W1=10
商品2:V2=100 W2=20
商品3:V3=120 W3=30
背包容量:W=50
那么对于0-1背包很明显不适合贪心算法,因为有可以背包装不满,不一定就是最优解
对于分数背包,肯定能装满,就可以用贪心算法
//分数背包
public void BackPack(float W=50f)
{
good[] goods = new good[] {
new good("钻石",60f,10f)
, new good("黄金",100f, 20f)
, new good("白银",120f, 30f) };
//分数背包,怎么拿,肯定先拿单位价值最高的啊,拿到装满或者没有为止
Array.Sort(goods);//先降序排列一下下
float[] indexAry = new float[] { 0, 0, 0};//计数
for (int i = 0; i < goods.Length; i++)
{
if (W>goods[i].Weight)//背包剩余大小够
{
indexAry[i] = 1;//全部拿走
Debug.Log(goods[i].Name + "拿走" + goods[i].Weight);
W -= goods[i].Weight;//更新背包
Debug.Log("背包还剩"+W);
}
else
{
indexAry[i] =W/ goods[i].Weight;//拿走部分
Debug.Log(goods[i].Name + "拿走" + (W / goods[i].Weight* goods[i].Weight).ToString());
W =0;//更新背包
Debug.Log("背包还剩" + W);
break;
}
}
PrintArry(indexAry,"");
}
商品(good)类就不贴出来了,不难,不过记得要继承IComparable,不然没法用内置的数组排序
测试一下
没问题
To be continued~~
第三个问题 数字拼接
有n个非负整数,将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?
例:32,94,128,1286,6,71 可以拼接的最大整数为94716321286128
贪心算法怎么解决,不是什么很高端的思路,比如128,1286怎么拼,你比一下128+1286和1286+128不就完事了
所以直接把这n个整数挨个比一下,排个序,再一起输出不就好了
//数字拼接
public void NumJoin(int[] numAry)
{
PrintArry(numAry,"需要拼接的数字");
Num[] snumAry = new Num[numAry.Length];
for (int i = 0; i < numAry.Length; i++)
{
snumAry[i] = new Num(numAry[i].ToString());
}
Array.Sort(snumAry);//降序排序
StringBuilder s = new StringBuilder();//输出拼接的数字
foreach (Num item in snumAry)
{
s.Append(item.Value);
}
Debug.Log(s);
}
Num类继承 IComparable,自定义一下比较的规则就好了,你也可以自己写排序算法,冒泡就很适合
测试一哈
To be continued~~
问题几来着,活动选择问题
假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能供一个活动使用。
每个活动都有一个开始时间si和结束时间fi,(题目中时间以整数表示),表示活动在[s,f)区间占用场地。
问:安排哪些活动能够使该场地举办的活动的个数最多?
首先我们肯定是优先安排最早结束的活动,其次防止活动时间重叠,也就是下一个活动的开始时间要>=上一个活动的结束时间
//活动选择
public void ActivityPlane()
{
Activity[] activities = new Activity[] {new Activity(1,4), new Activity(3, 5),
new Activity(0, 6) ,new Activity(5,7),new Activity(3,9),new Activity(5,9)
,new Activity(6,10),new Activity(8,11),new Activity(8,12),new Activity(2,14)
,new Activity(12,16)};
Array.Sort(activities);//升序
List resList = new List();
resList.Add(activities[0]);//第一个活动肯定是最先结束的活动
for (int i = 1; i < activities.Length; i++)
{
//防止活动时间重叠
if (activities[i].StartTime>=resList[resList.Count-1].EndTime)
{
resList.Add(activities[i]);
}
}
foreach (Activity item in resList)
{
Debug.Log(item.ToString());//重写了tostring方便debug
}
}
测试一哈
有点累了,让我康康,有么有番更新了,批里批里启动!