743. Network Delay Time(python+cpp)

题目:

There are N network nodes, labelled 1 to N.
Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the target node, and w is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? If it is impossible, return -1.
Note:
1.N will be in the range [1, 100].
2.K will be in the range [1, N].
The length of times will be in the range [1, 6000].
All edges times[i] = (u, v, w) will have 1 <= u, v <= N and 1 <= w <= 100.

解释:
无向图的最短路径:
Floyd算法可以算出图中所有节点之间的最短路径长度
Dijkstra算法只能求得某特定结点到其他所有结点的最短路径长度
这道题目是有向图,感觉可以用dfs做。
所有的结点都收到所需要的时间,就是每个结点都能收到的情况下,最迟收到信号的结点收到信号所需要的时间,如果有结点根本收不到信号那么就返回
解法参考《计算机考研机试指南的》p121 的Dijkstra算法解法。
python代码:

#邻接链表元素结构体
class E:
    def __init__(self,time,nxt):
        self.t=time
        self.next=nxt
class Solution(object):
    def networkDelayTime(self, times, N, K):
        """
        :type times: List[List[int]]
        :type N: int
        :type K: int
        :rtype: int
        """
        #邻接链表,如果内层不是数字的话,不要轻易写成乘法
        edge=[[] for _ in range(N+1)]
        #距离向量,当mark[i]为True时,表示已经得到的最短路径长度,否则表示所有从结点K出发,经过已知的最短路径到达
        #集合S中的某一点,再经过一条边到达结点i的最短距离
        Dis=[-1]*(N+1)
        Dis[0]=0
        #是否属于集合S,S数组保存当前最短路径的集合
        mark=[False]*(N+1)
        for time in times:
            a,b,c=time
            tmp1=E(c,b)
            edge[a].append(tmp1)
            # tmp2=E(c,a)
            # edge[b].append(tmp2)
        
        #起点为K
        Dis[K]=0
        mark[K]=True
        newP=K
        #循环n-1次,寻找其他n-1个结点的最短路径
        for i in range(1,N):
            #遍历与新加入的结点直接相连的边
            for j in range(len(edge[newP])):
                #该边的另一个结点
                tmpnext=edge[newP][j].next
                tmpt=edge[newP][j].t
                #若另一个结点也属于集合S,则跳过
                if mark[tmpnext]==True:
                    continue
                #若该点尚不可达到或者该点从新加入的结点经过一条边到达时比以往距离更短
                if Dis[tmpnext]==-1 or Dis[tmpnext]>Dis[newP]+tmpt:
                    Dis[tmpnext]=Dis[newP]+tmpt    
            #K经过已知的最短路径到达集合S中的某一点,再经过一条边到达结点i的最短距离
            _min=float('inf')
            #遍历所有结点
            for j in range(1,N+1):
                #若其属于集合S,则跳过
                if mark[j]==True:
                    continue
                #若该结点还尚未到达
                if Dis[j]==-1:
                    continue
                if Dis[j]<_min:
                    _min=Dis[j]
                    newP=j#新加入的点暂定为该点
            #加入到集合S中
            mark[newP]=True
        return -1 if -1 in Dis else max(Dis)

c++代码:

//邻接链表中的链表元素结构体
struct E
{
    int next;//代表直接相邻的结点,注意这里next不是指针
    int t;//代表改边的权重
};
class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        //邻接链表
        vector<vector<E>>edge(N+1,vector<E>());
        //设已经确定了最短路径长度的结点所构成的集合为集合S
        //标记,当mark[i]为true时,表示已经得到K到i的最短路径长度
        vector<bool>mark(N+1,false);
        //距离向量,mark[i]为true时,表示K到i的最短路径,否则表示从结点K出发到集合S中的某一点,再经过该点和i的连线到达i的距离
        vector<int>Dis(N+1,-1);
        //0结点不存在但是不能保持-1的值影响最终的结果
        Dis[0]=0;
        //构建邻接表
        for(auto time:times)
        {
            int a=time[0],b=time[1],c=time[2];
            E tmp;
            tmp.next=b;
            tmp.t=c;
            edge[a].push_back(tmp);//由于是有向图,所以这里只需要写一个
        }
        //起点为K
        Dis[K]=0;
        mark[K]=true;
        //集合S中新加入的结点为K
        int newP=K;
        //求其他N-1个结点的最短路径长度
        for (int i=1;i<N+1;i++)
        {   
            //遍历与新加入的结点newP相邻的所有结点
            for(int j=0;j<edge[newP].size();j++)
            {
                int tmpnext=edge[newP][j].next;//该边的另一个结点
                int tmpt=edge[newP][j].t;//该边的权重
                //如果该结点已经在集合S中,表示已经求得K到tmpnext的最短路径
                if(mark[tmpnext]==true)
                    continue;
                //若该结点尚不可达或者通过newP可以使得到达该结点的路径更短
                if(Dis[tmpnext]==-1 || Dis[tmpnext]>Dis[newP]+tmpt)
                {
                    Dis[tmpnext]=Dis[newP]+tmpt;
                } 
                
            }
            //接下来要找一个新的结点加入集合S,也就是要找一个到K的距离最短的结点加入到S
            int _min=INT_MAX;
            //遍历所有结点
            for(int j=1;j<N+1;j++)
            {
                //如果结点已经在S中,则跳过
                if(mark[j]==true)
                    continue;
                //如果该点仍不可到达,也跳过
                if(Dis[j]==-1)
                    continue;
                if (Dis[j]<_min)
                {
                    _min=Dis[j];
                    newP=j;//姑且先让该点成为新加入的结点,反正后面还要更新。
                }
            }
            //把newP加入集合S
            mark[newP]=true;
            
        }
        if (count(Dis.begin(),Dis.end(),-1)!=0)
            return -1;
        else
            return *max_element(Dis.begin(),Dis.end());
    }
};

总结:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值