• 最短路


    最短路

    多源最短路径

    Floyed-Warshall算法

    \[弗洛伊德算法,是最简单的多元最短路径算法,可以计算图中任意两点的最短路径。 时间复杂度为 O(N^3) \]

    算法描述:

    设置\(dis[u][v]\) 表示从\(u\)\(v\)的距离

    (1) 初始化

    将相连接的点的距离设置为 \(dis[u][v]\)=\(dis[v][u]\)

    如果不相连,则\(dis[u][v]=inf\)

    (2) 通过中间节点进行拓展

    	for(int k=1;k<=n;++k){
    		for(int i=1;i<=n;++i){
    			for(int j=1;j<=n;++j){
    				if(dis[i][j]>dis[i][k]+dis[k][j]&&dis[i][k]!=INF&&dis[k][j]!=INF){
    					dis[i][j]=dis[i][k]+dis[k][j];
    				}
    			}
    		}
    	}
    

    (3) 最终的出来的 dis[u][v] 则为u到v的最短路径

    Floyed 变形

    如果图为无边权图,且题求连通性,可以将 dis[u][v]=1,(相连) dis[u][v]=0(不相连)

    	for(int k=1;k<=n;++k){
    		for(int i=1;i<=n;++i){
    			for(int j=1;j<=n;++j){
    				dis[i][j]|=(dis[i][k]&&dis[k][j]);
    			}
    		}
    	}
    
    

    Dijkstra 算法

    \[Dijkstra 算法是一种单源最短路径算法,也就是说单次只能计算从一个起点到另外一个起点的最短路,时间复杂度是 O(N^2) ,但是不能处理负边权问题。 \]

    算法描述:

    设置起点为 s,那么dis[u] 则表示从s到v的最短路径,book[u] 则判断一个点是否被拓展过.(可以通过pre[u]记录前驱节点从而记录路径)

    (1)初始化

    \[dis[u]=inf \ \ \ u=1,2,3.....n(u\neq s) \\ book[u]=0 \ \ \ u=1,2,3.....n \\ dis[s]=0 \]

    (2) 拓展节点

    a.从未被访问的节点中找出一个顶点使得 \(dis[u]\) 是最小的

    b.将\(u\)标记为确定最短路

    c.对于每一个与\(u\)相连接的节点进行拓展更新最短路径

     for(int i=1;i<=n;++i){
            int minx=INF;
            int op=-1;
            for(int j=1;j<=n;++j){
                if(rdis[j]<minx && book[j]!=1){
                    minx=rdis[j];
                    op=j;
                }
            }
            if(op!=-1){
                book[op]=1;
                for(int j=1;j<=n;++j){
                    if(rdis[j]>rdis[op]+dis[op][j]&&!book[j]){
                        rdis[j]=rdis[op]+dis[op][j];
                        fa[j]=op;
                    }
                }
            }
        }
    

    (3) 最终求得的 dis[v] 则是s到v的最短路径

    Dijkstra 算法优化

    我们发现,对于每一次寻找最小值上述过程使用的都是遍历整个数组,但事实上我们可以不用遍历整个数组寻找最小值,对于最小值的寻找我们有着多种方法。

    堆优化

    我们只需要维护一个小根堆即可求得上述答案

    #include<bits/stdc++.h>
    using namespace std;
    const int size=100010;
    int n,m,s;
    int head[size],ver[2*size],Next[2*size],edge[2*size],tot;
    int dis[size],v[size];
    struct node{
    	int dis;
    	int num;
    	bool operator <(const node &x) const{
    		return x.dis<dis;
    	} 
    };
    priority_queue<node>q;
    void add(int x,int y,int z){
    	ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
    }
    void dija(){
    	memset(dis,0x3f,sizeof(dis));
    	memset(v,0,sizeof(v));
    	dis[s]=0;q.push((node){0,s});
    	while(q.size()){
    		int x=q.top().num;q.pop();
    		if(v[x]) continue;v[x]=1;//只能扩展一次
    		for(int i=head[x];i;i=Next[i]){
    			int y=ver[i];
    			if(dis[y]>dis[x]+edge[i]){
    				dis[y]=dis[x]+edge[i];
    				if(!v[y]){q.push((node){dis[y],y});}//这里不需要标记
    			}
    		}
    	}
    }
    int main(){
    	scanf("%d %d %d",&n,&m,&s);
    	for(int i=1;i<=m;++i){
    		int x,y,z;
    		scanf("%d %d %d",&x,&y,&z);
    		add(x,y,z);
    	}
    	dija();
    	for(int i=1;i<=n;++i){
    		printf("%d ",dis[i]);
    	}
    	return 0;
    }
    
    线段树优化
    #include<bits/stdc++.h>
    using namespace std;
    const int size=100010;const int N=100010,M=200010;
    inline long long read(){
        long long x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    struct node{
    	long long l,r,data,num;
    }t[4*N];
    int n,m,num,x,y,z,s,tot;
    long long k;
    const long long inf=1e18;
    bool v[N];
    int head[N],ver[M],Next[M],poi[N];
    long long edge[M],d[N];
    void add(int x,int y,int z){
    	ver[++tot]=y;edge[tot]=z;Next[tot]=head[x],head[x]=tot;
    }
    void build(long long p,long long l,long long r){
    	t[p].l=l,t[p].r=r;t[p].data=inf;
    	if(l==r){t[l].num=p;return;}
    	long long mid=(l+r)>>1;
    	build(p*2,l,mid);
    	build(p*2+1,mid+1,r);
    }
    void change(long long p,long long v){
    	p=t[p].num;t[p].data=v;
    	while(p>>=1,p){
    		t[p].data=min(t[p*2].data,t[p*2+1].data);
    	}
    }
    long long ask(){
    	int p=1;
    	while(t[p].l!=t[p].r){
    		if(t[p*2].data<t[p*2+1].data) p<<=1;
    		else p=p*2+1;
    	}
    	return t[p].l;
    }
    int main(){
    	n=read();m=read();s=read();
    	for(int i=1;i<=m;++i){
    		x=read();y=read();z=read();
    		add(x,y,z);
    	}
    	for(int i=1;i<=n;++i){
    		d[i]=inf;
    	}
    	d[s]=0;build(1,1,n);
    	change(s,0);	
    	for(int i=1;i<=n;++i){
    		int x=ask();
    		if(d[x]==inf) break;
    		for(int j=head[x];j;j=Next[j]){
    			int y=ver[j];
    			if(d[y]>d[x]+edge[j]){
    				d[y]=d[x]+edge[j];
    				change(y,d[y]);
    			}
    		}
    		change(x,inf);
    	}
    	for(int i=1;i<=n;++i){
    		if(d[i]!=inf) printf("%lld\n",d[i]);
    		else printf("-1\n");
    	}
    	return 0;
    }
    
  • 相关阅读:
    jQuery的鼠标悬停时放大图片的效果
    判断一个字符串在另一个字符串中出现的次数
    .net中几个经常用到的字符串的截取
    云服务器 ECS CentOS 7 下重启 sshd 服务操作方法
    博客生涯开始咯
    Json 转 Map 的几种方式
    JS 折线图
    CSS样式优先级
    Arrays.asList 数组转集合 java.lang.UnsupportedOperationException错误
    Netty 笔记
  • 原文地址:https://www.cnblogs.com/donkey2603089141/p/16197186.html
Copyright © 2020-2023  润新知