本题是个求最小值问题,题目描述:如果要在一年内去旅游,现给定你旅游的日期(1-365天)的数组,一个包日车票数组价格,比如包1天2块钱,包7天7块钱,包30天15块钱这样。求一年内能把所有规定日期都旅游完的最便宜买票策略。
例:
days[1,4,6,7,8,20],表明你要在1,4,6,7,8,20去旅游。(范围为1-365)
costs[2,7,15],表明1天的车票是2块钱,7天的车票是7块钱,30天的车票是15块钱。ps只有1、7、30天三种可选。
本题我没有解决,参考了一下别人的最后弄懂了,很巧妙。下面是我自己的理解。
首先1-365是一个一维长数组,在这个数组内,有的天需要旅游,有的天不需要旅游,我们先把需要旅游的天数标记为1,以days[1,4,6,7,8,20]为例,则这个数组f大概长这样
[1,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
这里是类似计数排序的一种思想去构造的数组,参考前面博客讲计数排序。加入动态规划的思想,从数组第0为开始计算,如果
f[0]==1,说明该天去旅游了,计算其需要的车票,那么我去从costs[2,7,15]去找最小的。答案是2。则f[0]==2
f数组长下面这样:
[2,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
接着
f[1]==0,说明该天没有去旅游,则该天的花费我们也可以看做是2,是为了传递这个价格,为后面做比较用。
f长这样
[2,2,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
继续第三次循环,
f[2]==0
则
[2,2,2,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
f[3]==1,则计算f[3-1]+costs[0]和f[3-7]+costs[1]和f[3-30]+costs[2]的最小值,3-7和3-30都是负数,我们取到0即可。f[0]=0。发现f[3-1]+costs[0]最小,为2+2=4
f数组长这样了
[2,2,2,4,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
f[4]==1,则f数组长这样
[2,2,2,4,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
f[5]同理
[2,2,2,4,4,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
f[6]
[2,2,2,4,4,6,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
f[7]时,f[7]==1,需要比较f[7-1]+costs[0]=8和f[7-7]+costs[1]=7和f[7-7]+costs[2]=15的值,最小的为f[7-7]+costs[1]=7
则f这次长这样
[2,2,2,4,4,6,7,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0...0]
依次类推。
代码:
public static int mincostTickets(int[] days, int[] costs) {
int length = days.length;
int f[] = new int[366];
for (int i = 0; i < days.length; i++) {
f[days[i]]=1;
}
for (int i = 1; i < 365; i++) {
if(f[i]==0){
f[i] = f[i-1];
}else{
f[i] = Math.min(f[i-1]+costs[0], Math.min(f[Math.max(i-7, 0)]+costs[1],f[Math.max(i-30, 0)]+costs[2]));
}
}
return f[days[length-1]];
}