最短路问题——Dijkstra算法模板

Dijkstra算法简介

Dijkstra算法主要用来解决边权为正时的单源最短路问题(就是从一个源点出发,到所有结点的最短路),同时适用于有向图和无向图

Dijkstra算法思路

Dijkstra算法模板

时间复杂度为O(n^2)

没有堆优化的代码
时间复杂度为O(n^2)

const int INF=1<<30;	
int v[maxn];
int d[maxn];
int w[maxn][maxn];

memset(v,0,sizeof(v));
for(int i=0;i<n;i++) d[i]=(i==0?0:INF);
for(int i=0;i<n;i++) {
	int x,m=INF;
	for(int y=0;y<n;y++) if(!v[y]&&d[y]<=m) m=d[x=y];
	v[x]=1;
	for(int y=0;y<n;y++) d[y]=min(d[y],d[x]+w[x][y]);
}

进行堆优化的代码
时间复杂度为O(mlogn)

struct edge{   //储存边
	int from,to,w;
	edge(int u,int v,int d):from(u),to(v),w(d){}
}
struct node{		//用来结合优先队列使用
	int d,u;
	bool operator < (const node &rhs) const {
		return d>rhs.d;
	}
}
vector<edge>edges;
vector<int>g[maxn];
int d[maxn];

void addedge(int from ,int to,int wei){   //加边函数,若为无向边,则调用addedge(u,v,w);addedge(v,u,w);各一次
	edges.push_back(edge(from,to,wei));
	m=edges.size();
	g[from].push_back(m-1);
}

void dij(){
	priority_queue<node> q;
	for(int i=0;i<=t;i++) d[i]=INF;
	d[s]=0;
	memset(done,0,sizeof(done));
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();q.pop();
		int u=x.u;
		if(done[u]) continue;
		done[u]=1;
		for(int i=head[u];~i;i=nxt[i]){
			if(d[to[i]]>d[u]+dis[i]){  	//松弛操作
				d[to[i]]=d[u]+dis[i];
				q.push((node){d[to[i]],dis[i]});
			}
		}
	}
}

递归打印最短路径

void print(int t){  //s为源点,t为终点	
	printf("%d  ",t);
	if(s==t) return;
	for(int i=0;i<n;i++){
		if(d[t]==d[t]+w[i][j]){
			print(i);
			break;
		}
	}
}

dij算法解决多源多汇问题

题目 HDU - 6166

AC代码

#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int maxn=100005;
const long long INF=0x3f3f3f3f3f3f3f3f;
int tot,k;
int head[maxn],done[maxn],a[maxn],mark[maxn];
long long d[maxn];
struct edge{
    int to,next;
    long long dis;
}edges[maxn];
struct node{
    int u;
    long long d;
    bool operator < (const node& rhs) const{
        return d>rhs.d;
    }
};
priority_queue<node>q;
void addedge(int from,int to,long long w){
    edges[tot].to=to;
    edges[tot].dis=w;
    edges[tot].next=head[from];
    head[from]=tot++;
}

long long dij(){
    while(!q.empty()){
        struct node x=q.top();q.pop();
        if(mark[x.u]) return x.d;
        if(done[x.u]) continue;
        done[x.u]=1;
        for(int i=head[x.u];~i;i=edges[i].next){
            if(d[edges[i].to]>d[x.u]+edges[i].dis){
                d[edges[i].to]=d[x.u]+edges[i].dis;
                q.push(node{edges[i].to,d[edges[i].to]});
            }
        }
    }
    return INF;
}

void init(){
    memset(done,0,sizeof(done));
    memset(mark,0,sizeof(mark));
    memset(d,0x3f3f3f3f3f3f3f3f,sizeof(d));
    while(!q.empty()) q.pop();
}

int main(){
    int t,n,m,kase=0;
    int u,v;
    long long w;
    scanf("%d",&t);
    while(t--){
        tot=0;
        memset(head,-1,sizeof(head));
        long long ans=INF;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w);
        }
        scanf("%d",&k);
        for(int i=0;i<k;i++) scanf("%d",a+i);
        for(int i=0;i<20;i++){
            init();
            for(int j=0;j<k;j++){
                if(a[j]&(1<<i)){
                    mark[a[j]]=1;
                }
                else q.push(node{a[j],d[a[j]]=0});
            }
            ans=min(ans,dij());
        }
        printf("Case #%d: %lld\n",++kase,ans);
    }
}

https://cn.vjudge.net/problem/766699/origin

这道题有多种思路。下面写的思路是设置一个古城中心,各个古城到古城中心设一条长度为x/2的无向边

ac代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<map>
using namespace std;
int t,n,k,m,s;
double X;
const int maxn=1e6;
int done[maxn];
double d[maxn];
struct edge{
    int from,to;
    double dis;
    edge(int u,int v,double d):from(u),to(v),dis(d){}
};
vector<edge>es;
vector<int>g[maxn];
struct node{
    double d;
    int u;
    bool operator <(const struct node & rhs) const{
        return d > rhs.d;
    }
};

void addedge(int u,int v,double d){
    es.push_back(edge(u,v,d));
    es.push_back(edge(v,u,d));
    int m=es.size();
    g[u].push_back(m-2);
    g[v].push_back(m-1);
}

void dij(int s){
    priority_queue<node>q;
    for(int i=0;i<=n;i++) d[i]=0x3f3f3f3f3f3f3f3f;
    d[s]=0;
    memset(done,0,sizeof(done));
    q.push((node){0,s});
    while(!q.empty()){
        node x=q.top();q.pop();
        int u=x.u;
        if(done[u]) continue;
        done[u]=1;
        for(int i=0;i<g[u].size();i++){
            edge& e=es[g[u][i]];
            if(d[e.to]>d[u]+e.dis){
                d[e.to]=d[u]+e.dis;
                q.push((node){d[e.to],e.to});
            }
        }
    }
}

int main(){
    scanf("%d",&t);
    while(t--){
        int a,b;
        double w;
        scanf("%d%d%lf%d%d",&n,&k,&X,&m,&s);
        for(int i=0;i<=n;i++) g[i].clear();es.clear();
        for(int i=0;i<m;i++){
            scanf("%d%d%lf",&a,&b,&w);
            addedge(a,b,w);
        }
        for(int i=1;i<=k;i++) addedge(0,i,X/2);
        dij(s);
        for(int i=1;i<=n;i++){
            if(i!=n) printf("%lld ",(long long)d[i]);
            else printf("%lld\n",(long long)d[i]);
        }
    }
    return 0;
}

如有错误,欢迎指出

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页