• Dijkstra算法略解


    Dijkstra 算法是一种用来解决单源最短路径的算法。参考资料

    给定一张 N N N 个节点、 M M M 条边的有向图,求从 1 号节点到每一个节点的最短路径长度。 N ≤ 1 0 5 , M ≤ 2 × 1 0 5 N≤10^5,M≤2×10^5 N105,M2×105

    一种很显然的思路是,如果 a->b 的最短路径经过 c,那么 a->b 的最短路径一定是 a->c 的最短路径和 c->b 的最短路径。也就是说,我们可以先求出较为好求的节点的最短路径(c),再根据这些数据来计算其他节点的最短路径(b)。

    什么节点的最短路径最好求?显然是被 1 号点直接指向的节点。当我们求出 1 号点及其直接指向的节点的最短路径以后,我们就可以使用他们来计算其他节点的最短路径。

    不难想到,1号点(a)到另一个不与 1 号点直接相连的点(b)的路径有很多条。如果我们对每条 a->b 的路径都遍历并更新,显然会超时(这也就是spfa算法不完美的原因)。考虑贪心,如果每次都尽量从与 1 号点最近的点出发开始遍历,那么遍历结束以后,新的与 1 号点最近的点的最短路径就已经被找到

    请思考加粗句为什么正确。

    假设这句话不正确,即新的与 1 号点最近的点( P P P)的最短路径( 1 → P 1 → P 2 → . . . → P n → P 1→P_1→P_2→...→P_n→P 1P1P2...PnP)仍未被找到。假设上次遍历的节点是 P 0 P_0 P0

    n = 0 n=0 n=0,说明 1 → P 1→P 1P 的距离比 P 0 → P P_0→P P0P 更短,则上次遍历不会更新后者而会更新前者,与更新规则矛盾;

    n ≠ 0 n≠0 n=0,说明 n − 1 n-1 n1(坑)。
    那么 P 0 P_0 P0

    如何寻找与 1 号点最近的点呢?用 set 维护,可以参考我的另一篇文章

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int MAXN=100010;
    const int MAXM=200010;
    
    struct edge{
    	int x, y, d, next;
    }e[MAXM];
    int len=0;
    int first[MAXN];
    int n, m;
    int s1, s2, s3;
    
    inline int read (){
    	int x=0; char c;
    	do c=getchar (); while ('0'>c||'9'<c);
    	while ('0'<=c&&'9'>=c)
    		x=x*10+c-48, c=getchar ();
    	return x;
    }
    void ins (int x, int y, int d){
    	e[++len].x=x; e[len].y=y; e[len].d=d;
    	e[len].next=first[x]; first[x]=len;
    }
    struct pir{
    	int x, dis;
    	pir (){
    		x=dis=0;
    	}
    };
    bool operator< (const pir a, const pir b){
    	if (a.dis!=b.dis) return a.dis<b.dis?1:0;
    	return a.x<b.x?1:0;
    }
    set<pir> s;
    int dis[MAXN], tf[MAXN];
    
    int main (){
    	n=read (); m=read (); read ();
    	for (int i=1; i<=m; ++i){
    		s1=read (); s2=read (); s3=read ();
    		ins (s1, s2, s3);
    	}
    	memset (dis, 63, sizeof (dis)); dis[1]=0;
    	memset (tf, 0, sizeof (tf));
    	pir p; p.x=1; p.dis=0;
    	s.clear (); s.insert (p); 
    	for (int i=1; i<n; ++i){
    		pir nw=*s.begin (); int x=nw.x;
    		tf[x]=1; s.erase (nw); 
    		for (int i=first[x]; i; i=e[i].next){
    			int y=e[i].y;
    			if (tf[y]) continue;
    			p.x=y; p.dis=dis[y]; s.erase (p);
    			dis[y]=min (dis[y], dis[x]+e[i].d);
    			p.dis=dis[y]; s.insert (p);
    		}
    	}
    	for (int i=1; i<=n; ++i)
    		printf ("%d ", dis[i]);
    }
    
  • 相关阅读:
    Linux——Linux用户管理、组管理和文件管理常用命令总结
    [轻笔记] SHAP值的计算步骤
    保单识别易语言代码
    HarmonyOS ArkUI实战开发-NAPI数据类型
    Spring(十五)- Spring注解方式整合第三方框架
    Java接口Json数组入参转换为指定List<Entity>
    [C++] Reference
    Jmeter接口自动化生成测试报告html格式
    【软考软件评测师】第三十二章 数据库系统基础知识
    04 【折线图】
  • 原文地址:https://blog.csdn.net/YangHao5/article/details/127093947