思路:我们可以先从第一站开始找,比如在0–>1–>3|0–>2–>3中,我把第一站定义为0–>1|0–>2。先找第一个也就是在k=1时
也就是0–>1|0–>2时,它们各自的价格。然后开始找k-n(0<n<k)个站的价格、一直找到第k个站的价格。
比如k=2,就要找1–>3|2–>3,这个时候因为有前面0–>1|0–>2的基础,我们可以合起来就有0–>1–>3|0–>2–>3的价格
了,这个时候我们发现1–>3跟2–>3终点重合起来了,这个时候我们就要判断他们两个方案的最小价格了。所以按照这个推理
我们也可以推理k=3,k=4…一直到k=k。 总结一下我们这个思路,就是把k化成每一个小问题,比如上面那个例子,K=2,我们先找K=1时各站的价格,然后在k=1的基础上
找k=2的价格、k=3的价格…,最后得出在K-1的基础上,找到K的最优解。
算法设计:按照思路,我们要一个数组存每一个终点站的价格。
如果是一维数组:
状态:dp[i] = 价格;i代表每一个终点站
状态转移方程:dp[flights[j][1]] = Math.max(dp[flights[j][1]],dp[flights[j][0]]+flights[2]);
这个时候,我们发现,随着j的增大,我们在寻找出k=1后,会马上寻找k=2,接着又是寻找k=1,然后是k=2。比如:
在上面思路中我们说到,先找0-->1|0-->2,然后再找1-->3|2-->3。第一站肯定是从起始点出发,然后再计划下一站。
我们现在这个设计不能做到上面的效果
//说明一下:这个可以计算起点到目的地的最优解,但不能确定中转站数。
解决方案:两个数组。
状态:dp_1[i] = 价格;dp_2[i] = 价格;i代表每一个终点站
状态转移方程:dp_1[flights[j][1]] = Math.max(dp_1[flights[j][1]],dp_2[flights[j][0]]+flights[2]);
初始化:dp_1[起点] = 0;dp_2[起点] = 0;
dp_1[其他] = Integer.MAX_VALUE/2;dp_2[其他] = Integer.MAX_VALUE/2;
在0-->1-->3中,当k = 1时,我们让1-->3不能录入数据。
在0-->2-->3中,当k = 1时,我们让2-->3不能录入数据。
只有在k=2时,我们才让1-->3|2-->3录入
所以,我们根据题目的提示,得到:最大的价格不会超过100*10000元。我们给两个dp初始化比100*10000大的数。
然后起点站初始化0;两个数组交替使用,k=1时用dp_1,k=2时用dp_2;k=3时用dp_1...
flights = {[0,1,20],[1,3,10],[0,2,10],[2,3,5]} --->[起点,终点,价格]
分析:k = 1时,我们dp_1[0] = 0,dp_1[1] = Math.min(dp_1[1],dp_2[0]+flights[0]])
dp_1[3] = Math.min(dp_1[2],dp_2[1]+flights[1]])--->这步很重要,dp_1[2]此时 = Integer.MAX_VALUE/2;
dp_2[1]此时 = Integer.MAX_VALUE/2;再加上flights[1]就会比dp_1[3]大了,所以dp_1[3]还是等于Integer.MAX_VALUE/2;
结论:我们因此可以得出,这个方案符合我们的思路
public static int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
int dp_1[] = new int[n];
int dp_2[] = new int[n];
int MAX = Integer.MAX_VALUE/2;
//初始化(因为100*10000=100000<MAX)
for (int i = 0;i < n;i++){
dp_1[i] = MAX;
dp_2[i] = MAX;
}
dp_1[src] = 0;
dp_2[src] = 0;
//K是中转站数
for(int i = 0;i <= K;i++){
for(int item[]: flights){
//这里我们存dp_1时,要用到dp_2来做判断
if((~i & 1) == 0)
dp_1[item[1]] = Math.min(dp_1[item[1]],dp_2[item[0]]+item[2]);
else
dp_2[item[1]] = Math.min(dp_2[item[1]],dp_1[item[0]]+item[2]);
}
}
int money = dp_1[dst]>dp_2[dst]?dp_2[dst]:dp_1[dst];
//如果不存在就返回-1
if(money == MAX) money=-1;
return money;
}