zoukankan      html  css  js  c++  java
  • 常用算法模板程序集锦 第一集:并查集 最短路径

    1 并查集模板函数

    int a[100]; 
     //初始状态,每个点的父亲是自己或者0,即每个点各是一个集合。 
    int InitSet(int MemberNum)
    {
        for(int i=0;i<MemberNum;i++)
            a[i]=i;    
    /* 
        for(int i=0;i<=MemberNum-1;i++)
            a[i]=0;    
        */        
    }
     int rootfind(int x)
    {
        if(a[x]==x) 
            return (x);
        else
            a[x]=rootfind(a[x]);
            return (a[x]);
    //或者    return(a[x]==x?x:a[x]=rootfind(a[x]))
    }
    //合并两个根节点,即合并两个集合。先找根节点,在调用此函数,
    //也可以不用函数 
    void UnionRoot(int r1,int r2)
    {
        a[r2] = r1;
    }
    struct union_find_set { //超级简洁的并查集   
    //一个并查集结构体 面向对象的思想 将变量和函数封装起来。实现了并查集的初始化,找祖先和合并操作 
        int n,fa[MAXN];
        void init(int N) {
            n=N;
            for (int i=1;i<=n;i++) fa[i]=i;
        }
        int getFather(int u) {
            while (u=fa[u]=fa[fa[u]],u!=fa[u]);
            return u;
        }
        bool set_union(int u,int v) {
            return (u=getFather(u))==(v=getFather(v)) ? false : fa[v]=u;
        }
    } ufs;

    2 最短路径算法

      Dijkstra、spfa、foyd、Bellman-Ford四种算法的比较。

      Dijkstra:求单源最短路径,仅适用于正权图,时间复杂度:o(n2),可用小根堆优化

      Bellman-Ford:求单源最短路径,适用于正权图和负权图,判断并找出负权回路。时间复杂度:o(NM)

      Spfa(Bellman-Ford的队列优化算法): 求单源最短路径,适用于正权图和负权图,判断并找出负权回路,时间复杂度:o(VM)

      Foyd:求多源最短路径,适用于正权图,时间复杂度:o(n3)

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    struct Edge{
        int to,w;
    };
    vector<Edge>E[1010];//下标从1开始
    int dist[1010];//下标从1开始 
    bool used[1010];//下标从1开始
    const int MAX=1000000010;
    int main()
    {
        int i,j,u,v,t,n,m,s;
        scanf("%d%d%d",&n,&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&t);
            E[u].push_back((Edge){v,t});
            E[v].push_back((Edge){u,t});
            //有向图版:E[u].push_back((Edge){v,t});
            //无向图要存两条边 
        }
        for(i=1;i<=n;i++)
            dist[i]=MAX;
        dist[1]=0;//源点为1 
        int k,Min;
        for(i=0;i<n-1;i++)//迪杰斯特拉算法,这里控制循环次数,必须保证n-1次循环 
        {
            //在没确定最短路径的点中寻找路径最短的点,将它作为下一步的中转点 
            Min=MAX;
            for(j=1;j<=n;j++)
                if(Min>dist[j] && used[j]==0)
                {
                    k=j;
                    Min=dist[j];
                }
            s=k;
            used[s]=1;
            //松弛 
            for(j=1;j<E[s].size();j++)
                dist[E[s][j].to]=min(dist[E[s][j].to],dist[s]+E[s][j].w);
        }
        printf("%d",dist[n]);
    }

    2.2迪杰斯特拉算法优化

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    using namespace std;
    const int N=100010;
    struct Edge{int to,len;};
    vector <Edge> E[N];
    int n,m;
    long long dist[N];
    bool used[N];
    struct Point{
        int no;
        long long dist;
        friend bool operator > (const Point A, const Point B){
            return A.dist!=B.dist?A.dist>B.dist:A.no>B.no;
        }
    };
    priority_queue <Point, vector<Point>, greater<Point> > Q;
    void Dijk(int st){
        memset(dist, 0x3f, sizeof(dist));
        dist[st]=0ll;
        Q.push((Point){st,0ll});
        while(!Q.empty()){
            int now=Q.top().no;
            Q.pop();
            if(used[now]) continue;
            used[now]=1;
            for(int i=0;i<E[now].size();i++){
                if(dist[E[now][i].to]>dist[now]+E[now][i].len){
                    dist[E[now][i].to]=dist[now]+E[now][i].len;
                    Q.push((Point){E[now][i].to, dist[E[now][i].to]});
                }
            }
        }
    }
    int main(){
        int S;
        scanf("%d%d%d", &n,&m,&S);
        for(int i=0;i<m;i++){
            int s,t,d;
            scanf("%d%d%d", &s,&t,&d);
            E[s].push_back((Edge){t,d});
        }
        Dijk(S);
        for(int i=1;i<=n;i++) printf(i<n?"%lld ":"%lld
    ", dist[i]);
        return 0;
    }

    2.3 弗洛伊德算法

    #include <iostream>
    using namespace std;
    const int INF=1e9;
    int N, M, dist[1010][1010];
    void floyd(){
        for(int k=1;k<=N;k++)
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
    }
    int main(){
        scanf("%d %d", &N, &M);
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                dist[i][j]=(i==j?0:INF);
        for(int i=0;i<M;i++){
            int s,t,d;
            scanf("%d %d %d", &s, &t, &d);
            dist[s][t]=min(dist[s][t], d);
        }
        floyd();
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                printf(j<N?"%d ":"%d
    ", dist[i][j]);
        return 0;
    }

     2.4 SPFA

    void spfa()
    {
        memset(used,0,sizeof(used));
        memset(dist,0x3f,sizeof(dist));
        int i,s;
        queue <int> q;
        used[1]=1;
        q.push(1);
        dist[1]=0;
        while(!q.empty())
        {
            s=q.front();
            q.pop();
            used[s]=0;//队头出队,并将队头used标记设为0,即不在队中
            for(i=0;i<E[s].size();i++)
            if( dist[s]+E[s][i].w<dist[E[s][i].to])//用刚出队的点作为中转点即松弛点,松弛它的所有邻接点。
            {
                dist[E[s][i].to]=dist[s]+E[s][i].w;
                if(used[E[s][i].to]==0)//被更新的邻接点如果不在队中,则入队并改变是否在队列中的标记
                {
                    q.push(E[s][i].to);
                    used[E[s][i].to]=1;
                    /* 
                    //以下几行是为了判断环:若一个点入队的次数等于n次,则存在负权环
                    times[i]++;
                    if(times[i]>=n)
                    {
                        printf("-1");
                        return 0;
                    }
                    */
                }    
            }    
        }
    
    }
    
    
    
  • 相关阅读:
    swarm集群搭建 及集群维护操作
    zabbix 告警说明
    yum 下载安装包
    mongdb常见操作
    cloudera5.16.1 离线安装
    centos7 安装hadoop-3.2.1
    rpcbind 启动报错
    ingress-nginx 安装
    Dubbo学习
    mybatis防止SQL注入
  • 原文地址:https://www.cnblogs.com/StoneXie/p/9445546.html
Copyright © 2011-2022 走看看