魔法城市路径问题(腾讯2017校招笔试题)

腾讯校招的笔试题目:魔法城市路径问题
魔法城市
时间限制:(每个case)2s 空间限制:128MB

小Q来到一个魔法王国,这个王国一共有n个城市,分别是0~n-1号魔法城市,任意两个城市都有一条魔法通道连通(无向边),每条魔法通道都需要一定的时间才能通过。小Q现在在0号魔法城市,他希望通过穿梭魔法通道到达1号魔法城市。
小Q为了更快到达1号魔法城市,在魔法商店购买了一把魔力扫把,使用魔力扫把在一条魔法通道飞行的时候可以让该魔法通道花费的时间减半,但是魔法扫把最多只能使用k次,小Q想知道他从0号魔法城市到1号魔法城市需要多少时间。

输入:
输入包括n+1行。
第一行中有两个正整数n,k(2<= n <= 50, 0 <= k <= 50),分别代表城市数量和魔法扫把可以使用的次数,以空格分割。
接下来n行,每行一个长度为n的字符串dis[i][j](‘0’ <= dis[i][j] <= ‘9’)表示从i号魔法城市到j号魔法城市需要的时间。
对于所有合法的 i和 j 满足dis[i][j] = dis[j][i]
对于所有合法的 i 满足dis[i][i] = 0

输出
输出一个实数表示的小Q从0号魔法城市到1号魔法城市最少需要的时间,答案保留一位小数。

样例输入:
3 2
094
904
440
样例输出:
4.0

这个题就是一个无向图的路径问题,在每个路径上设置了行走时间,相当于是路径的权值。这里采用的是暴力破解,循环递归来实现,因为魔法扫把会让时间减半,所以一定要用在每一条通路上的行走时间最长的那几段路径,这样总时间才会减半最多。

package others;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

public class MagicCity {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int city_num = 3;   //城市数目
        int saoba_num = 2;   //扫把使用次数
        int[][] time = {{0, 9, 4},  //城市魔法通道的时间
                        {9, 0, 4},
                        {4, 4, 0}};
        //链表的每个元素存储着单一通路的行走时间,遍历链表中的元素。
        ArrayList<int[]> arr = magicCity(city_num, saoba_num, time);
        //遍历链表中的元素,打印所有可能的通路
        System.out.println("############# 打印所有通路  ###############");
        Iterator<int[]> it1 = (Iterator<int[]>) arr.iterator();
        while(it1.hasNext()){  
            int[] temp = (int[]) it1.next();
            for(int i = 0; i < temp.length; i++) {
                if(i < temp.length -1) System.out.print(temp[i] + ",");
                else                   System.out.print(temp[i]);
            }
            System.out.println();
        }  
        System.out.println("############# 打印通路最少时间  ############");
        //遍历链表中的元素,打印所需时间最少的通路所用时间。
        int min_time = 2^32;  //设置一个初始最大时间。
        Iterator<int[]> it2 = (Iterator<int[]>) arr.iterator();
        while(it2.hasNext()){  
            int[] temp = (int[]) it2.next();
            Arrays.sort(temp);  //对每个的通路时间进行排序
            int mux_time = 0;
            for(int i = 0; i < temp.length; i++) {
                if(i == temp.length || i == temp.length -1) {
                    mux_time = mux_time + temp[i] / 2;
                }
            }
            if(mux_time < min_time) min_time = mux_time;
        }  
         System.out.println(min_time);
    }   
    private static ArrayList<int[]> magicCity(int city_num, int saoba_num, int[][] time) {
        ArrayList<int[]> arr = new ArrayList<int[]>();
        ArrayList<String> arr_temp = new ArrayList<String>();
        String[] cities = new String[city_num];
        for(int i = 0; i < city_num; i++) {  //给city_num城市标号
            cities[i] = Integer.toString(i);
        }
        arr_temp.add(cities[0]);   //出发的城市
        magicCity(cities, saoba_num, time, arr, arr_temp);
        return arr;
    }

    private static void magicCity(String[] cities, int saoba_num, int[][] time, 
            ArrayList<int[]> arr, ArrayList<String> arr_temp) {
        if(arr_temp.contains(cities[1])) {  //递归结束条件,到达终点城市1。
            int[] temp = new int[arr_temp.size() - 1];
            //下面这部分代码是找到了所有可能的通路,并把通路的时间按行走顺序进行了存储
            for(int k = 0; k < arr_temp.size() - 1; k++) {
                int m = Integer.parseInt(arr_temp.get(k));
                int n = Integer.parseInt(arr_temp.get(k+1));
                temp[k] = time[m][n];
                /*
                 * 为了节省内存,可以在这个地方就对数组temp进行排序,然后得到单一通道的时间,然后把时间进行存储。
                 */
            }
            arr.add(temp);
            return;
        }
        for(int j = 1; j < cities.length; j++) {  //递归的主体部分
            if(!arr_temp.contains(cities[j])) {
                arr_temp.add(cities[j]);
                magicCity(cities, saoba_num, time, arr, arr_temp);
                arr_temp.remove(arr_temp.size() - 1);
            }
        }
    }
}

代码运行效果:

############# 打印所有通路  ###############
9
4,4
############# 打印通路最少时间  ############
2
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值