力扣每日一题:882. 细分图中的可到达节点【最短路径dijkstra】

给你一个无向图(原始图),图中有 n 个节点,编号从 0 到 n - 1 。你决定将图中的每条边 细分 为一条节点链,每条边之间的新节点数各不相同。

图用由边组成的二维数组 edges 表示,其中 edges[i] = [ui, vi, cnti] 表示原始图中节点 ui 和 vi 之间存在一条边,cnti 是将边 细分 后的新节点总数。注意,cnti == 0 表示边不可细分。

要 细分 边 [ui, vi] ,需要将其替换为 (cnti + 1) 条新边,和 cnti 个新节点。新节点为 x1x2, ..., xcnti ,新边为 [ui, x1][x1, x2][x2, x3], ..., [xcnti+1, xcnti][xcnti, vi] 。

现在得到一个 新的细分图 ,请你计算从节点 0 出发,可以到达多少个节点?如果节点间距离是 maxMoves 或更少,则视为 可以到达 。

给你原始图和 maxMoves ,返回 新的细分图中从节点 0 出发 可到达的节点数 。

示例 1:

输入:edges = [[0,1,10],[0,2,1],[1,2,2]], maxMoves = 6, n = 3
输出:13
解释:边的细分情况如上图所示。
可以到达的节点已经用黄色标注出来。

示例 2:

输入:edges = [[0,1,4],[1,2,6],[0,2,8],[1,3,1]], maxMoves = 10, n = 4
输出:23

示例 3:

输入:edges = [[1,2,4],[1,4,5],[1,3,1],[2,3,4],[3,4,5]], maxMoves = 17, n = 5
输出:1
解释:节点 0 与图的其余部分没有连通,所以只有节点 0 可以到达。

提示:

  • 0 <= edges.length <= min(n * (n - 1) / 2, 104)
  • edges[i].length == 3
  • 0 <= ui < vi < n
  • 图中 不存在平行边
  • 0 <= cnti <= 104
  • 0 <= maxMoves <= 109
  • 1 <= n <= 3000

 

分析:题目意思从源点0出发,最大距离能走maxMoves,然后求出可到达的节点数。题目给出了edges数组,这个就是边和权值,我们有了边和权值,就能最初源点到其他点的最短路径。这里的在初始化权值的时候要注意,这个不能要加1,因为自己就是一个点,然后加上自己就是要加上1,然后用dijkstra求出最短路径。得到最短距离dist数组,计算原始图中所有可达节点的数量,加入结果中。

然后再考虑细分边上的节点。我们考虑某一条边上的两个节点。让这两个节点分别沿着这条边继续往对方节点走,看看有多少个细分节点是可达的。如果它们相遇了,也就是他们走过的节点数量大于这条边上的细分节点数量,那么说明这条边上的所有细分节点都是可达的。否则,将他们走过的节点数量加入到结果中。

AC代码:

class Solution {
   int res=0 ;
    int [][] map ;
    int dist[];


    public int reachableNodes(int[][] edges, int maxMoves, int n) {
        map= new int[n][n] ;
        dist = new int[n];
     
     //进行初始化
        for (int[] ints : map) {

            Arrays.fill(ints,Integer.MAX_VALUE);
        }
        Arrays.fill(dist,Integer.MAX_VALUE);
        for (int[] edge : edges) {
           //这里所有的距离都加1,加上自己的那个点
            map[edge[1]][edge[0]] = edge[2]+1 ;
            map[edge[0]][edge[1]] = edge[2]+1 ;
        }
        dijkstra(0,map,dist);

        for(int d : dist){
            
            if(d<=maxMoves){
                res++ ; 
            }
        }

        for (int[] edge : edges) {
            int a = edge[0] , b =edge[1] , cnta  = 0 ,cntb= 0 ;

            if (dist[a]<maxMoves){
                //看看还能多走几个细分节点
                cnta = Math.min(edge[2],maxMoves-dist[a]);
            }
            if (dist[b]<maxMoves){
                cntb= Math.min(edge[2],maxMoves-dist[b]);
            }

            res+= Math.min(edge[2],cntb+cnta) ;

        }


        return res ;

    }

    public void dijkstra(int v , int [][]a ,int dist[]){

        int n = dist.length-1 ;
        if (v<0||v>=n ){
            return;
        }

        //标记是否访问
        boolean [] isVisited = new boolean[n+1] ;
        for (int i =0 ;i<=n ;i++){
            dist[i] = a[v][i] ;
            isVisited[i] =false ;
        }

        //自己到自己为0
        dist[v] = 0 ;
        isVisited[v] =true ;

        //遍历所有能通的点
        for (int i = 0 ;i<= n;i++){
            int temp = Integer.MAX_VALUE ;
            int u =v ;
            for (int j =0 ;j<=n;j++){
                //如果没有访问,而且距离小于temp,最小值就交换
                if (!isVisited[j]&&temp>dist[j]){
                    u=j ;
                    temp=dist[j] ;
                }
            }

            //标记u点访问过了
            isVisited[u] = true ;

            //在从u点找到u到其他点最小值
            for (int j = 0;j<=n;j++){
                if (!isVisited[j]&&a[u][j]<Integer.MAX_VALUE){
                    int newDist = dist[u] + a[u][j] ;
                    if (newDist<dist[j]){
                        dist[j] = newDist;

                    }
                }
            }
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little Chen1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值