zoukankan      html  css  js  c++  java
  • 最短路

    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("此图包含有负权回路
    ");
            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
  • 相关阅读:
    《Programming WPF》翻译 第6章 3.二进制资源
    《Programming WPF》翻译 第5章 前言
    谈谈粒子系统
    GameFramework的初步设计
    引擎层次化设计
    关于HeapCreate(1)
    新的引擎ZeusEngine
    最短路径算法介绍
    Max导出插件
    游戏中的光影效果
  • 原文地址:https://www.cnblogs.com/iwomeng/p/11503424.html
Copyright © 2011-2022 走看看