看了前几个问题感觉CPU曲线和象棋问题思考起来蛮简单,对于CPU曲线的问题还是比较生疏的因为之前没有接触过这样的问题,之前一直搞cocos2dx,总想着做出像样的手机游戏,一直没研究过算法,前几天投了几个相关实习生招聘,感觉笔试考的都是数据结构及算法问题,之前学做过一个手机游戏,用到了A*寻路算法,难到了,顿时感觉算法学习起来虽然枯燥(相比于做游戏的直观),但是基础牢固学习什么应该都很轻松,于是最近研究起了算法,也算是为找工作做准备吧。
之前看了烙饼排序问题,刚刚看觉得觉得很“简单”(因为没看清要求,粗心),后来再学习的过程中感觉要写下学习过程以备后续回看。由于意识到这个问题时已经看到了买书问题就从这开始,随后补上欠的。
刚看到题目,买书有折扣,多买多打折,要求找出打折最多的买法。看完题目脑海中根据经验自然就想到了根据所买卷数由最大打折方法看齐,先取最大折扣,以此类推,很简单嘛,可是继续深入学习感觉自己不够细心,或者说是自己根本没有静下心去仔细思考。
之后发现如果按最大折扣选择后出问题,书中也给出了反例,如买8卷的情形,取5+3(5*0.25+3*0.1=1.55)不如4+4(4*0.2*2=1.6)折扣大,这显然与选择策略有违。针对反例,提出解法。
针对优先选择打折扣的贪婪算法,书中说“10本以上理论上都能拆解为表1—1出现的组合”,我就在想这句话对不对,就用最笨的方法将11~20本书的情形推算了一下,确实可行。所以将10本以内的情况研究好基本上就解决问题了。
看着书中不断地“卷卷”的出现有点乱乎,不如就书店就只有5本不同的书,针对这5本书进行买卖。
对5本书购买数为{B1,B2,B3,B4,B5},根据贪婪算法,理应满足大折扣规律,即有B1>=B2>=B3>=B4>=B5,优先选择5本的情况,其次4本,3本,2本,1本。
解法一
第一种可能:根据我的理解针对解法一的第一种可能,将10本以上的书分成小于10本的情形,对于16本书(3,4,4,3,2)的情况,如果分成10与6,由贪婪算法应对应2*(1,1,1,1,1)与(1,1,1,0,0)、(0,1,1,1,0)折扣为2.5+2*0.3=3.1;而将其分成2*(1,1,1,1,0)、(0,1,1,1,1,)和(1,1,1,0,1)对应折扣为0.8*4=3.2显然与将多于10本书的情形分成少于10本的局部的方法有违,第一种可能不可行。
第二种可能:第二种可能针对的是表1-1中的反例5+3比4+4的折扣低,将所买书的总数分成不同的组合借用例子(7,6,5,3,2)分成5+5+4+3+3+2+1,由反例调整成4+4+4+4+4+2+1的组合。主要思想是利用贪婪算法针对反例不断进行调整,个人感觉这种方法是可行的并无不合理之处。
解法二
运用动态规划,进行一步,针对现有情形做出选择,第一步可以选择5本(4,3,2或者1)然后根据情形继续选择,这种方法利用穷举将所有可能遍历,最后选出价格最低的情形。
//5个数最小值
int min(int y1,int y2,int y3,int y4,int y5)
{
int min1 = (y1>y2?y2:y1);
int min2 = (y3>y4?y4:y3);
int min3 = (min1>min2?min2:min1);
int min = (y5>min3?min3:y5);
return min;
}
//冒泡排序用于转换成最小表示
void bubble(int*a,int n)
{
int i, j, temp;
for (i = 0; i <n - 1;i++)
{
for (j = i + 1; j < n;j++)
{
if (a[i] <a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
//递归主函数,返回最小价格
int lowerprice(int a[5])
{
bubble(a,5);
int p1, p2, p3, p4, p5;
if (a[1] ==a[2] == a[3] == a[4] == a[0] == 0)return 0;
while(a[1]>0&&a[2]>0&&a[3]>0&&a[4]>0&&a[0]>0)
{
int buf[5];
for (int j = 0; j < 5;j++)
{
buf[j] = a[j];
}
if (a[4] >= 1)
{
for (int i = 0; i < 5; i++)
{
buf[i] = a[i] - 1;
}
p1 = 5 * 8 * (1 - 0.25) + lowerprice(buf);
}
if (a[3]>=1)
{
for (int i = 0; i < 4;i++)
{
buf[i] = a[i] - 1;
}
p2 = 4 * 8 * (1 - 0.2) + lowerprice(buf);
}
if (a[2] >= 1)
{
for (int i = 0; i < 3; i++)
{
buf[i] = a[i] - 1;
}
p3 = 3 * 8 * (1 - 0.1) + lowerprice(buf);
}
if (a[1]>=1)
{
for (int i = 0; i < 2; i++)
{
buf[i] = a[i] - 1;
}
p4=2 * 8 * 0.95 + lowerprice(buf);
}
if (a[0] >= 1)
{
for (int i = 0; i < 1; i++)
{
buf[i] = a[i] - 1;
}
p5 = 8 + lowerprice(buf);
}
}
return min(p1, p2, p3, p4, p5);
}