队列操作篇 -- 旅行问题

题目描述

牛客网:NC522旅行Ⅰ
牛妹出去旅行啦,她准备去N个城市旅行,去每个城市的开销是Ai 元。但是牛妹有强迫症,她想在去y城市之前先旅游x城市,于是牛妹列出了这些限制条件list。并且牛妹很节约,她只有V元,她每次会选择当前能去的花费最小的城市,如有多个花费一样的则首先去编号小的城市,她想知道她最多能到多少个城市去旅游。
示例

输入:3,10,[3,7,8],[(1,2)]
返回值:2
参数说明:
3:城市总数,编号从1 -> N
10:总金额
[3,7,8]:城市的开销
[(1,2)]:代表旅游顺序限制,先去x号城市才能再去y号城市

题目解析

1. 拓扑排序

首先判断所给条件:

  1. 每个城市开销已知
  2. 最大花费金额已知
  3. 旅游城市有顺序限制
  4. 每次选取花费最少的城市或编号最小的城市

可以把城市看做点,构成有向图,使用拓扑排序思想从中找出满足条件的遍历路径。

拓扑排序思路如下:

  1. 找到所有入度为0的节点,加入队列
  2. 删除队列中的一个节点,并将其指向的所有节点的入度值减1
  3. 若有入度值为0的城市,加入队列
  4. 重复上述操作,直至队列为空。此时没有入度值为0的节点,要么遍历完成,要么图中有环。

2. 题目求解

根据拓扑排序思路解决本题。

  • 首先创建数组,根据给出的限制列表得到每个城市的入度值后续城市
  • 需要对队列中的城市进行排序,可以使用优先队列建立最小堆,保证每次获取的都是花费最少编号最小的城市。
  • 遍历列表,统计满足条件的城市数量

代码如下

/*表示去 y 城市前要先去 x 城市*/
public class Point {
   int x;
   int y;
   public Point(int x, int y) {
     this.x = x;
     this.y = y;
   }
}

public class Solution {
    /**
     * @param N : N个城市
     * @param V : 总金额V元
     * @param A : 每个城市的花费
     * @param list: 旅游顺序限制
     * @return int整型:最多可旅游的城市数
     */
    public int Travel (int N, int V, int[] A, Point[] list) {
         //记录城市的入度,城市从1开始编号
        int[] indeg = new int[N + 1];
        //记录每个城市的后序城市
        int[][] aftCity = new int[N + 1][N + 1];
        // 初始化入度值和后续城市
        for(Point point : list){
            indeg[point.y]++;
            aftCity[point.x][point.y] = 1;
        }
        // 用一维数组存储城市的编号和花费
        PriorityQueue<int[]> queue = new PriorityQueue<>(
              (o1,o2) -> o1[1] == o2[1] ? o1[0] - o2[0] : o1[1] - o2[1]
        );
        for(int i = 1;i <= N;i++){           
            // 入度为0则加入队列
            if(indeg[i] == 0){
                queue.offer(new int[]{i,A[i - 1]});
            }
        }
        // 遍历城市
        int count = 0;        
        int[] curCity = new int[2];
        while(!queue.isEmpty()){
            curCity = queue.poll();
            if(curCity[1] > V){
                break;
            }
            //前往该城市
            V -= curCity[1];
            count++;               
            // 将后序城市的入度减1
            for(int i = 1;i <= N;i++){
                if(aftCity[curCity[0]][i] == 1){
                    indeg[i]--;
                    if(indeg[i] == 0){
                        queue.offer(new int[]{i,A[i - 1]});
                    }
                }               
            }          
        }
        return count;      
}
  • 时间复杂度:初始化辅助数组及遍历城市的时间复杂度为O(n),队列的添加删除操作时间复杂度为O(logn),因此最终的时间复杂度为O(n*logn)
  • 空间复杂度为:O(n2)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值