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

    1、floyd-warshall

    思路

    枚举中转站
    时间复杂度:(O(n^3))
    使用范围:多源点最短路

    #include<bits/stdc++.h>
    using namespace std;
    int e[100][100],k,i,j,n,m,t1,t2,t3;
    const int inf=99999;
    int main()
    {
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    		for(j=1;j<=n;j++)
    			if(i==j)e[i][j]=0;
    				else e[i][j]=inf;
        for(i=1;i<=m;i++)
        {
        	cin>>t1>>t2>>t3;
        	e[t1][t2]=t3;
    	}
    	
    	for(k=1;k<=n;k++)
    		for(i=1;i<=n;i++)
    			for(j=1;j<=n;j++)
    				if(e[i][j]>e[i][k]+e[k][j])
    				e[i][j]=e[i][k]+e[k][j];
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			printf("%ld ",e[i][j]);
    		}
    	}
    	return 0;
    }
    
    

    2、Dijkstra算法

    思路:

    bfs的思路,从s的邻边开始,选出最短边,再从下一个起点开始,选最短边,期间不停地更新dis,
    ,此时按照贪心的原理,每次选择离s最短的作为起点,标记后dis不必更新。
    使用范围:无负权值的单源点最短路
    时间复杂度:(O(n^2))

    #include <iostream>
    #include <vector>
    using namespace std;
    struct edge{int to;int cost;};
    vector<edge>g[50005];//相当于一个二维数组,存储edge 
    int d[50005];
    int vis[50005];
    int n;
    const int inf=2147483647;
    int djs(int s)
    {   
        int min1,k;
        for(int i=1;i<=n;i++) d[i]=inf;
            d[s]=0;//初始化 
            for(int i=1;i<n;i++)
            {
                min1=inf;k=s;
    
                for(int j=1;j<=n;j++)//寻找离源点最近的且未标记点
                if (!vis[j]&&min1>d[j])
                    {min1=d[j];k=j;}
                vis[k]=1;//标记
                for(int j=0;j<g[k].size();j++)//重点j从0开始更新未标记的终点to
                {  
    				int tm=g[k][j].to;
                    if(!vis[tm]&& min1+g[k][j].cost<d[tm])
                        d[tm]=min1+g[k][j].cost; 
                }
            }
         return 0;
    
    }
    
    int main()
    {   
    	ios::sync_with_stdio(false);
        int m,s,x;
        cin>>n>>m>>s;//输入点边源
        edge tmp;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>tmp.to>>tmp.cost;
            g[x].push_back(tmp);//压入g[起点]
        }
        djs(s);
        for(int i=1;i<=n;i++)
            cout<<d[i]<<" ";
    
        return 0;
    }
    

    堆优化的djs

    djs的思路是每次取出dis最小的点,以它为起点更新dis,并且把这个点标记为已知,那么就可以用堆得数据结构降低时间复杂度,取出最小点,并将与之连接的点放入堆中,直至堆空

    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    struct edge
    {
        int to,cost;
    };
    vector<edge>g[500005];//定义路径结构体
    int n,m,s;
    int dis[500005];
    struct node//定义堆结构体
    {
    	//(如果看不懂)https://www.cnblogs.com/ZERO-/p/9347296.html
    	int u,d;
    	bool operator<(const node&rhs)const
    	{
    		return d>rhs.d;
    	}
    };
    inline void djs()
    {
    	for(re int i=1;i<=n;i++)dis[i]=2147483647;
    	dis[s]=0;
    	priority_queue<node>Q;//初始化
    	
    	node a ={s,0};
    	Q.push(a);//第一个node
    	
    	while(!Q.empty())
    	{
    		node fr=Q.top();Q.pop();
    		int u=fr.u,d=fr.d;
    		//取出并记录
    		if(d!=dis[u])continue;//避免处理无用数据,也就是dis[u]已经更新,之前未更新数据直接出栈,比如有一组数据 2 5,但是后面又入栈一组数据2 3,则2 5是无用数据
    		for(re int j=0;j<g[u].size();j++)
    		{
    			int tm=g[u][j].to;
    			if(dis[u]+g[u][j].cost<dis[tm])
    			{			 
                	dis[tm]=dis[u]+g[u][j].cost;
    				Q.push((node){tm,dis[tm]});
    			}
    		}
    	}
    }
    int main()
    {
    	cin>>n>>m>>s;
    	int x;
    	for (re int i=1;i<=m;i++)
    	{
            edge tmp;
          	cin>>x>>tmp.to>>tmp.cost;
            g[x].push_back(tmp);   
        }
        djs();
     	for (re int i=1;i<=n;i++)
      	printf("%d ",dis[i]);    
    	return 0;
    }
    
    

    3、动态规划

    思路

    更新更新

    #include<bits/stdc++.h>
    using namespace std;
    long long dis[10100];
    int u[500100],v[500100],w[500100],n,m,s,check;//我们定义一个check,优化用 
    const int inf=2147483647;
    int main()
    {
        cin>>n>>m>>s;//输入 
        for(int i=1;i<=m;i++)
            cin>>u[i]>>v[i]>>w[i];//读入边 
        for(int i=1;i<=n;i++)
            dis[i]=inf;//dis数组初始化 
        dis[s]=0;
        for(int k=1;k<=n-1;k++)
        {
            check=0;//check归零 
            for(int i=1;i<=m;i++)
            {
                if(dis[v[i]]>dis[u[i]]+w[i])
                {
                    dis[v[i]]=dis[u[i]]+w[i];
                    check=1;//如果dis数值改变,check赋值为1 
                }   
            }
            if(check==0)
                break;//如果没变,直接跳出循环,不要浪费时间 
        }
        for(int i=1;i<=n;i++)
            cout<<dis[i]<<" ";//输出 
        return 0;//好习惯
    }
    

    4、SPFA算法

    P3385 【模板】负环

    #include<bits/stdc++.h>
    const long long inf=2147483647;
    const int maxn=10005;
    const int maxm=500005;
    using namespace std;
    int n,m,s,num_edge=0;
    int dis[maxn],vis[maxn],head[maxm];
    struct Edge
    {
      int next,to,dis;
    }edge[maxm]; //结构体表示静态邻接表
    void addedge(int from,int to,int dis) //邻接表建图
    { //以下是数据结构书上的标准代码,不懂翻书看解释
      edge[++num_edge].next=head[from]; //链式存储下一条出边
      edge[num_edge].to=to; //当前节点编号
      edge[num_edge].dis=dis; //本条边的距离
      head[from]=num_edge; //记录下一次的出边情况
    }
    void spfa()
    {
      queue<int> q; //spfa用队列,这里用了STL的标准队列
      for(int i=1; i<=n; i++) 
      {
        dis[i]=inf; //带权图初始化
        vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
      }
      q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
      while(!q.empty())
      {
        int u=q.front(); //取出队首
        q.pop(); vis[u]=0; //出队标记
        for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
        {
          int v=edge[i].to; 
          if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
          {
            dis[v]=dis[u]+edge[i].dis;
            if(vis[v]==0) //未入队则入队
            {
              vis[v]=1; //标记入队
              q.push(v);
            }
          }
        }
      }
    }
    int main()
    {
      cin>>n>>m>>s;
      for(int i=1; i<=m; i++)
      {
        int f,g,w;
        cin>>f>>g>>w; 
        addedge(f,g,w); //建图,有向图连一次边就可以了
      }
      spfa(); //开始跑spfa
      for(int i=1; i<=n; i++)
        if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
          else cout<<dis[i]<<" "; //否则打印最短距离
      return 0;
    } //结束
    

    vector版本的spfa

    
    struct edge
    {
    	int v,w;
    };
    vector<edge>g[10001];
    int d[10001];
    int times[10001];
    bool vis[10001];
    queue<int>q;
    int n;
    void spfa(int s)
    {
    	memset(vis,0,sizeof(vis));
    	memset(d,inf,sizeof(d));
    	memset(times,0,sizeof(times));
    	while(!q.empty())q.pop();
    	q.push(s);
    	vis[s]=1;
    	d[s]=0;
    	times[s]=1;
    	while(!q.empty())
    	{
    		int now=q.front();
    		q.pop();
    		vis[now]=0;
    		for(int j=0;j<g[now].size();j++)
    		{
    			edge p=g[now][j];
    			if(d[p.v]>d[now]+p.w)
    			{
    				d[p.v]=d[now]+p.w;
    				times[p.v]++;
    				debug(times[p.v]);
    				if(times[p.v]>n)
    				{
    					puts("YES");
    					return;
    				}
    				if(!vis[p.v])
    				{
    					q.push(p.v);
    					vis[p.v]=1;;
    				}
    			}
    		}
    	}
    	puts("NO");
    }
    main(void)
    {
    	int t=read(),m;
    	for(re int i=1;i<=t;i++)
    	{
    		n=read();
    		m=read();
    		int u,v,w;
    		for(re int j=1;j<=m;j++)
    		{
    			edge t;
    			u=read(),v=read(),w=read();
    			t.v=v;
    			t.w=w;
    			g[u].push_back(t);
    			t.v=u;
    			if(w>=0)g[v].push_back(t);
    		}
    		spfa(1);
    		for(int j=1;j<=n;j++)
    			g[j].clear();
    	}
    }
    
    

    参考:题解

  • 相关阅读:
    高精度计算模板
    P1108 低价购买 [DP][统计方案]
    POJ3349 Snowflake Snow Snowflakes [哈希]
    P1312 Mayan游戏 [深搜][模拟]
    P1378 油滴扩展[深搜]
    P1514 引水入城[搜索,线段覆盖]
    TYVJ1391 走廊泼水节
    【BZOJ1196】公路修建问题
    【BZOJ3624】免费道路
    【BZOJ2429】聪明的猴子
  • 原文地址:https://www.cnblogs.com/wangqianyv/p/13584630.html
Copyright © 2011-2022 走看看