Loading

最短路

DFS

求1到n的最短路径

vis[1]=1;
dfs(1,0);
void dfs(int cur,int dis) {
    if(dis>mini) return ;
    if(cur==n) {
        mini=min(mini,dis);
        return ;
    }
    for(int i=1;i<=n;i++) {
        if(e[cur][i]!=inf && !vis[i]) {
            vis[i]=1;
            dfs(i,dis+e[cur][i]);
            vis[i]=0;
        }
    }
}
View Code

 


 

Dijkstra (O(n2))

求s到其他点的最短距离,无法求含负权边图

思路:用一个dis数组存1号到其他顶点的初始路程,选一条离1号最近的边,dis[2]就确定了,考虑2号顶点的出边,进行一次松弛操作,接下来继续从未选的顶点中选一条离1号最近的边,继续如上操作。

View Code

 

 


 

 

Bellman-Ford 

无负环的情况可以使用

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
const int inf=1<<25;
int T,n,m,cases;
struct edge {
    int u,v,w;
}a[maxn];
int path[maxn],dis[maxn];
bool Bellman(int s) {
    for(int i=0;i<n;i++) dis[i]=inf,path[i]=-1;
    dis[s]=0;
    for(int i=0;i<n;i++) { ///迭代n次,如果第n次还在更新,说明有负环
        bool flag=0;
        for(int j=0;j<m;j++) {
            int x=a[j].u,y=a[j].v;
            if(dis[x]<inf && dis[x]+a[j].w<dis[y]) {
                dis[y]=dis[x]+a[j].w;
                path[y]=x;
                flag=1;
                if(i==n-1) return true;///返回真,真的存在负环
            }
        }
        if(!flag) break;///如果没更新了,说明已经松弛完毕
    }
    for(int i=0;i<n;i++) {
        if(i==s) continue;
        printf("从%d到%d距离是:%2d   ", s,i,dis[i]);
        stack<int>q;
        int x=i;
        while(path[x]!=-1) {
            q.push(x);
            x=path[x];
        }
        cout<<s;
        while(!q.empty()) {
            cout<<"->"<<q.top();
            q.pop();
        }
        cout<<endl;
    }
    return false;
}
int main() {
    cin>>n>>m;
    for(int i=0;i<m;i++) cin>>a[i].u>>a[i].v>>a[i].w;
    if(Bellman(0)) cout<<"存在负环"<<endl;
    else cout<<"不存在负环"<<endl;
    return 0;
}
View Code
#include<bits/stdc++.h>
const int inf=0x3f3f3f3f;
using namespace std;
int main( ) {
    int u[100],v[100],w[100],dis[100],n,m,ck,flag;
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>u[i] >> v[i] >> w[i];
    memset(dis,inf,sizeof(dis)); dis[1]=0;
    for(int k=1;k<=n-1;k++) {
        ck=0; ///用来标记本轮松弛操作中数组dis是否会发生更新
        for(int i=1;i<=m;i++) {
            if(dis[v[i]]>dis[u[i]]+w[i]) {
                 dis[v[i]]=dis[u[i]]+w[i];
                 ck=1;  ///数组dis发生更新,改变check的值
            }
        }
        if(ck==0) break;   ///如果dis数组没有更新,提前退出循环结束算法
    }
    flag=0;
    for(int i=1;i<=m;i++) {
        if(dis[v[i]]>dis[u[i]]+w[i])
        flag=1;
        if(flag==1) printf("此图包含有负权回路\n");
        else {
            for(int i=1;i<=n;i++) printf("%d ",dis[i]);
            return 0;
        }
    }
    return 0 ;
}
View Code

 队列优化:每次仅对最短路估计值发生变化了的顶点的所有出边进行松弛

#include <iostream>
#include <cstring>
using namespace std;
#define inf 0x3f3f3f3f
int u[8],v[8],w[8],first[6],net[8],dis[6],vis[6];
int main() {
    int n,m;
    cin>>n>>m;

    memset(dis,inf,sizeof(dis)); dis[1]=0;
    memset(vis,0,sizeof(vis));
    memset(first,-1,sizeof(first));

    for(int i=1;i<=m;i++) {
        cin>>u[i]>>v[i]>>w[i];
        net[i]=first[u[i]];
        first[u[i]]=i;
    }

    int que[101],head=1,tail=1;
    que[tail++]=1;
    vis[1]=1;

    while(head<tail) {
        int k=first[que[head]];
        while(k!=-1) {
            if(dis[v[k]]>dis[u[k]]+w[k]) {
                dis[v[k]]=dis[u[k]]+w[k];
                if(!vis[v[k]]) {
                    que[tail]=v[k];
                    tail++;
                    vis[v[k]]=1;
                }
            }
            k=net[k];
        }
        vis[que[head]]=0;
        head++;
    }
    for(int i=1; i<=n; i++) cout<<dis[i]<<" ";
    return 0;
}
View Code

 

 


 

 

SPFA

求s到t的最短路

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
#define inf 0x3f3f3f3f
queue<int>q;
const int maxn=1e5;
int dis[maxn],vis[maxn],cost[maxn];
int from[maxn],to[maxn];
int net[maxn],head[maxn];
int n,m,s,t;
int k; ///边数

void add(int u,int v,int w) {
    ///from表示边的出发点,to为边的到达点
    from[++k]=u; to[k]=v;
    net[k]=head[u];
    head[u]=k;
    cost[k]=w;
}

void spfa(int s) { ///以s为起点的所有点的最短路
    for(int i=1;i<=n;i++) dis[i]=inf;
    memset(vis,0,sizeof(vis));
    vis[s]=1; dis[s]=0;
    q.push(s);
    while(!q.empty()) {
        int u=q.front(); q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=net[i]) {
            int v=to[i];
            if(dis[v]>dis[u]+cost[i]) {
                dis[v]=dis[u]+cost[i];
                if(!vis[v]) q.push(v);vis[v]=1;
            }
        }
    }
}

int main( ) {
    k=0;
    memset(head,-1,sizeof(head));
    cin>>n>>m>>s>>t;
    for(int i=1;i<=m;i++) {
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    spfa(s);
    cout<<dis[t];
    return 0;
}
View Code
#include <bits/stdc++.h>
#define maxn 500009
using namespace std;
#define inf 0x3f3f3f3f
int dis[maxn],net[maxn],to[maxn],w[maxn],head[maxn];

int n,m,s;

queue<int> q;
int tot=0;
bool vis[maxn];
void add(int x,int y,int z) {
    net[++tot]=head[x];
    head[x]=tot;
    w[tot]=z;
    to[tot]=y;
}
void spfa(int u) {
    memset(dis,inf,sizeof(dis)); dis[u]=0;
    memset(vis,0,sizeof(vis)); vis[u]=1;
    q.push(u);
    while(!q.empty()) {
        int x=q.front(); q.pop();
        vis[x]=0;
        for(int i=head[x];i;i=net[i]) {
            int y=to[i];
            if(dis[x]+w[i]<dis[y]) {
                dis[y]=dis[x]+w[i];
                if(!vis[y]) vis[y]=1,q.push(y);
            }
        }
    }
}
int main( ) {
    cin>>n>>m>>s;///s为起点
    for(int i=1;i<=m;i++) {
        int x,y,z;
        cin>>x>>y>>z;
        add(x,y,z);
    }
    spfa(s);
    for(int i=1;i<=n;i++) printf("%d ",dis[i]);
    return 0;
}
View Code

 


 

Floyd-Warshall

求任意两个点之间的最短路径

void Floyd() {
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            path[i][j]=-1;
            if(i==j) e[i][j]=0;
            else e[i][j]=inf;
        }
    }
    for(int k=1;k<=n;k++) {
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=n;j++) {
                if(e[i][j]>e[i][k]+e[k][j]) {
                    path[i][j]=k;
                    e[i][j]=e[i][k]+e[k][j];
                }
            }
        }
    }
}
void print(int u,int v) {
    if(path[u][v]==-1) return ;
    print(u,path[u][v]);
    cout<<path[u][v]<<"->";
}
View Code

 

posted @ 2019-09-10 22:12  qinuna  阅读(137)  评论(0编辑  收藏  举报