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

    dijkstra写法

    邻接矩阵

    
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define r read()
    const int maxn = 1e4;
    const int INF = 0x3f3f3f3f;
    int n,m,q;
    int G[maxn][maxn];
    bool vis[maxn];/// 标记位
    int close[maxn];///最近距离所在的终点
    int dis[maxn];///最近的距离
    void out(int x)
    {   
        if(x==q){cout<<x<<' ';return ;}
        out(close[x]);
        cout<<x<<' ';
    }
    signed  main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	cout.tie(0);
    	memset(G,INF,sizeof(G));///  按照逻辑含义  不存在的边的长度为无穷大  但是边相同的会被覆盖
    	memset(vis,false,sizeof (vis));
            memset(close,-1,sizeof(close));
    	///freopen("1.txt","r",stdin);
    	///freopen("2.txt","w",stdout);
    	cin>>m>>n>>q;///n条边  m个顶点
    	for (int i=0;i<n;++i)
    	{
    		int u;
    		int v;
    		int w;
    		cin>>u>>v>>w;
    		G[u][v] = w;
    	}
    	for (int i=1;i<=m;++i)
    	{
    		dis[i] = G[q][i];///  首次更新  确立v1为永久点
    		if (!vis[i] && dis[i]!=INF) close[i] = q;///  和当前永久点相连最近
    	}
    	int idx = q;
    	vis[q] = true;
            dis[q] = 0;
    	for (int i=1;i<m;++i)
    	{
    		int mine = INF;
    		for (int k=1;k<=m;++k)
    		{
    			if(!vis[k]&&dis[k]<mine)
    			{
    				mine = dis[k];
    				idx = k;
    			}
    		}   /// 找出当前的最小临时点  设为永久点
    		vis[idx] = true;///   设为永久点  进行标记
    		/// cout<<close[idx]<<' '<<idx<<endl;
    		for (int j=1;j<=m;++j)
    		{
    			if (!vis[j]&&dis[idx]+G[idx][j] < dis[j])/// 更新永久点相连的顶点
    			{
    				close[j] = idx;
    				//sum -= dis[j];
    				dis[j] = dis[idx]+G[idx][j];
    				//sum += dis[j];
    			}
    		}
          }
          /*for (int i=1;i<=m;++i)
          {
             cout<<close[i]<<' ';
          }*/
          ///puts("");
          out(m);
          return 0;
    }
    
    /*
        dijkstra算法    本种写法针对于无重边的情况  ,主要采用的思想是贪心
        每次利用上一次得到的永久点进行更新
        首先将起始点设为永久点  然后对于和永久点相连的边进行更新   更新最短的距离dis[i]
        然后对于剩余的临时点查找其中的最小值设为新的永久点  用当前的永久点进行更新
        如此往复  每次更新到当前最近的距离的顶点   对于记录vq到所有点的最短路径,进行回溯  
    */
    

    邻接表写法

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define r read()
    const int maxn = 1e4;
    const int INF = 0x3f3f3f3f;
    int n,m,q;
    bool vis[maxn];
    int dis[maxn];///   储存从开始位置当当前下标节点的最短距离
    int close[maxn];  ///储存最短距离最近的顶点编号
    struct vex_edge ///    头节点结构
    {
        struct edge_Node *first_Node;///   储存第一个边节点
    }G[maxn];
    struct edge_Node
    {
        int idx;///   跟G[i]-idx   表示 从i到idx的边
        int weight;/// 权重
        struct edge_Node * next_edge;///   下一个边节点  
    };
    void out(int x)
    {   
        if(x==q){cout<<x<<' ';return ;}
        out(close[x]);
        cout<<x<<' ';/// 逆序输出
    }
    void   init()/// 初始化
    {
        memset(vis,false,sizeof(vis));
        memset(close,-1,sizeof(close));
        memset(dis,INF,sizeof(dis));
        for (int i=1;i<=m;++i)   G[i].first_Node = NULL;///  头节点首先为空   此时是不存在的头节点   只是一个指针
        /// 有需要也可以自行弄一个头节点
    }
    signed main()
    {
        cin>>m>>n>>q;/// n条边   m个节点  q是开始出发的起点
        init();/// 初始化
        for (int i=1;i<=n;++i)
        {
            int u,v,w;
            cin>>u>>v>>w;
            struct edge_Node*p;
            p = (edge_Node*)malloc(sizeof(edge_Node));
            p->idx = v;
            p->weight = w;
            p-> next_edge = G[u].first_Node;  ///  插入操作  将所有的链节点放到p之后
            G[u].first_Node = p;
        }
        /*
        for (int i=1;i<=m;++i)
        {
            struct edge_Node *op;
            op =  G[i].first_Node;
            cout<<i<<' ';
            while (op!=NULL)
            {
                cout<<op->idx<<' '<<op->weight<<' ';
                op = op ->next_edge; G[q].first_Node;
            }
            cout<<endl;
        }
        */
        struct edge_Node *op;
        op = G[q].first_Node;
        while (op != NULL)  /// 找出跟q相连的边节点
        {
            dis[op->idx] = op->weight;
            close[op->idx] = q;
            ///cout<<op->weight<<endl;
            op = op ->next_edge;
        }
    	int id = q;
    	vis[q] = true;
        dis[q] = 0;  ///
        close[q] = q;/// 最后回溯路径的基础条件
    	for (int i=1;i<m;++i)
    	{  
    		int mine = INF;
    		for (int k=1;k<=m;++k)
    		{
    			if(!vis[k]&&dis[k]<mine)
    			{
    				mine = dis[k];
    				id = k;
    			}
    		}   /// 找出当前的最小临时点  设为永久点
    		vis[id] = true;///   设为永久点  进行标记
            ///cout<<id<<endl;
    		/// cout<<close[idx]<<' '<<idx<<endl;
            struct edge_Node *T;
            T = G[id].first_Node;
            while (T!=NULL)
            {
                if (!vis[T->idx]&&dis[T->idx] > (dis[id]+(T->weight)))
                {
                    close[T->idx] = id;
                    dis[T->idx] = dis[id] +T->weight;
                   /// cout<<T->idx<<' '<<dis[T->idx]<<endl;
                }
                T = T->next_edge;
            }
        }
        for (int i=1;i<=m;++i)
           cout<<close[i]<<' ';
       puts("");
       for (int j=1;j<=m;++j) out(j),puts("");/// 输出每一条最短路径
       return 0;
    }
    

    堆优化

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define r read()
    const int maxn = 1e6+7;
    const int INF = INT_MAX;
    int n,m,q;
    struct Node{
        int v;
        int c;
        Node(int vv=0,int cc=0):v(vv),c(cc){}
        bool operator <(const Node &res)const {
            return  c>res.c;
        }///  堆顶为小  小根堆
    };
    struct Edge{
        int v,weight;///  到当前节点的最短距离
        Edge(int vv=0,int cc=0):v(vv),weight(cc){}
    };
    
    vector<Edge> G[maxn];
    bool  vis[maxn];
    int dis[maxn];
    void Dijkstra(int start)
    {
        memset(vis,false,sizeof(vis));
        for (int i=1;i<=m;++i)dis[i] = INF;
        priority_queue<Node>que;
        while (!que.empty()) que.pop();///清除
        dis[start] = 0;
        que.push(Node(start,0));///  插入
        Node tmp;
        while (!que.empty())
        {
            tmp = que.top();
            que.pop();
            int u = tmp.v;///找到当前永久点的编号
            if (vis[u]) continue;
            vis[u] = true;
            for (int i=0;i<G[u].size();++i)
            {
                int v = G[tmp.v][i].v;///和永久点相连的其他点
                int weig = G[u][i].weight;///永久点到其他顶点的距离
                if (!vis[v] && dis[v]>dis[u]+weig)///更新
                {
                    dis[v] = dis[u] + weig;
                    que.push(Node (v,dis[v]));///记录
                }
            }
        }
    }
    void insert_edge(int u,int v,int w)
    {
        G[u].push_back(Edge(v,w));
    }
    signed main()
    {
        cin>>m>>n>>q;
        ///for(int i=1;i<=m;i++)G[i].clear();
        for (int i=1;i<=n;++i)
        {
            int u,v,w;
            cin>>u>>v>>w;
            insert_edge(u,v,w);
        }
        Dijkstra(q);
        for (int i=1;i<=m;++i) cout<<dis[i]<<' ';
        puts("");
        return 0;
    }
    
    齐芒行,川锋明!
  • 相关阅读:
    罗马数字转换成整数
    整数转换成罗马数字
    hdu 5050 大数
    hdu 5051 找规律?+大trick
    hdu 5055
    hdu 5054
    hdu 5058 set应用
    hdu 5056 所有字母数都<=k的子串数目
    hdu 5059 简单字符串处理
    hdu 5060 五种情况求圆柱体与球体交
  • 原文地址:https://www.cnblogs.com/qimang-311/p/14090551.html
Copyright © 2011-2022 走看看