数据结构 最短路径和最小生成树

单源最短路和多源最短路

本来我今天要是搞懂了线段树我就想写线段树的模板,还是要几天去消化一下里面的道理。所以今天就炒一炒冷饭吧,嘻嘻。可能大家都了解这些代码,毕竟是数据结构的主要内容,但是自己实现起来还是不一样的,可以敲一敲我发的题目。
多源最短路 弗洛伊德算法
先发题目链接 hdu 2066 戳这里
先写这个主要是这个思路比较清晰,容易写一点,缺点就是时间复杂度比较高,如果不去剪枝的话很容易超时,不过剪枝的难度不高,所以总体来说求所有点的最短路径用这个就对了。
这个算法的核心思想就是一个三重循环,最外层的循环我们可以把它叫做中间点(意思就是 如果我们要求两个点的最短距离 需要判断这两个点的最短路程需不需要这这第三个点的参与),里面的一个二重循环你可以理解为起点和终点。(所以按照2066 可以敲一下)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
#define MAXN 5000
int d[1001][1001];  /*存信息*/
int main()
{
    int t,s,q;
    while(cin>>t>>s>>q)
    {
            int c[10001],e[10001];
         int min=10000000,maxd=-1;
         for(int i=0;i<1001;i++)
          for(int j=0;j<1001;j++)
           {  if(i==j)
               d[i][j]=0;
               else
               d[i][j]=MAXN;
            } /*初始化图信息*/
            for(int i=0;i<t;i++)
            {    int a,b,time;
                cin>>a>>b>>time;
                if(b>maxd)
                  maxd=b;
                if(a>maxd)
                  maxd=a;
                  /*因为该题没说图的边界问题,所以只能找最远的点为边界了*/
                  if(d[a][b]>time)   
                  {
                d[a][b]=time;
                d[b][a]=time;
                  }
                  /*考虑重边的情况,找最小的边*/
            } 
              for(int k=0;k<=maxd;k++)
               {
                     for(int i=0;i<=maxd;i++)
                      {
                          if(d[i][k]!=MAXN)
                          for(int j=0;j<=maxd;j++)
                        if(d[i][j]>(d[k][j]+d[i][k]))
                          d[i][j]=d[k][j]+d[i][k];
                       } 
                } 
            /*弗洛伊德算法*/
                for(int i=0;i<s;i++)   
                     cin>>c[i]; 
                for(int j=0;j<q;j++)
                     cin>>e[j];
                     for(int i=0;i<s;i++)
                       for(int j=0;j<q;j++)
                         if(d[c[i]][e[j]]<min&&d[c[i]][e[j]]!=0) 
                            min=d[c[i]][e[j]];
                cout<<min<<endl;
                /*最后找一条最短的输出*/
    }
} 

类似的还有一道 hdu 1599 戳这里不过这一道题需要一个弗洛伊德最小环的判定定理,想了解的可以自己百度。
单源最短路径 迪杰特斯拉算法
单源最短我还没敲过,所以特意去敲了一道题(我自己都有点爱我自己)
hdu 2544 戳这里
具体思想

  1. 确定你要求的起点。
  2. 按照你的起点初始化你的距离信息(就是起点到各个点的距离,如果到不了就设为一个较大值表示为无法到达)。
  3. 然后选取一个最小的边,连接起来,再修改距离的信息(如果起点经过该点再到终点的距离 小于 从起点到终点的距离就修改信息。
  4. 最后当遍历完所有点以后,数组里面的信息就是最短路径了。
    下面是AC代码 注意(无穷大值一定要蛮大 不然报错)
#include<iostream>
#include<string.h>
#include<stack>
#include<queue>
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200000
int map1[500][500];
int d[500];
int vis[500];
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0)
        break;
        memset(d,0,sizeof(d));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++)
            map1[i][j]=MAXN;

        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            if(map1[a][b]==0)
            {
                map1[a][b]=c;
                map1[b][a]=c;
            }
            else if(c<map1[a][b])
            {
                map1[a][b]=c;
                map1[b][a]=c;
            }   
        }
        for(int i=1;i<=n;i++)
            d[i]=map1[1][i];
        for(int i=1;i<=n;i++)
        {
            int temp=MAXN;
            int k;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j]&&d[j]<temp)
                {
                    temp=d[j];
                    k=j;
                }
            }
            vis[k]=1;
            for(int j=1;j<=n;j++)
            d[j]=min(d[j],d[k]+map1[k][j]);
        }
          cout<<d[n]<<endl;
    }
} 

最小生成树 克鲁斯卡尔算法
为什么不讲prime 因为我觉的那个方法不好理解,还容易和最短路径搞混,所以我超级讨厌用那个算法,如果想学prime 请出门右转。
hdu 1301 戳这里
具体思路
1.思路就一点 把你的所有路径的大小都排个序(升序),然后不断选最小边(如果成环就要舍弃那条要成环的边),并且用一个变量去记住累加的权值,最后输出就行了(关于判断环的方法,我采用了一点并查集的思想)不会并查集的百度,或者看代码自己理解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
#define MAXN 5000
int map1[1001][1001];
int f[1001];
int n,m;
char a;
struct node{
    int s;
    int e;
    int value;
};
bool cmp(node x,node y)
{
    return x.value<y.value;
}
int find(int x)
{    int r=x;
    while(r!=f[r])
    r=f[r];
    int i=x,j;
    while(i!=r)
    {
        j=f[i];
        f[i]=r;
        i=j;
    }
    return r;
}
void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    f[fx]=fy;
}
int main()
{     
     while(cin>>n&&n!=0)
     {int k=0;
       int cost=0;
       node p[1001];
         for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
      {
          if(i==j)
          map1[i][j]==0;
          else
          map1[i][j]=MAXN;
      }
     for(int i=0;i<n-1;i++)
    {
          cin>>a>>m;
          for(int j=0;j<m;j++)
          {     char b;
                 int value;
                 cin>>b>>value;
              map1[(int)(a-65)][(int)(b-65)]=value;
              map1[(int)(b-65)][(int)(a-65)]=value;
        }
    }    
    for(int i=0;i<n;i++)
        f[i]=i;
    for(int i=0;i<n;i++)
     for(int j=0;j<=i;j++)
      {
          if(map1[i][j]!=MAXN&&map1[i][j]!=0)
          {       
             p[k].s=i;
             p[k].e=j;
             p[k].value=map1[i][j];
             k++;
        }
      }
      sort(p,p+k,cmp);
      for(int i=0;i<k;i++)
      {
          if(find(p[i].s)!=find(p[i].e))
          {
              join(p[i].s,p[i].e);
              cost+=p[i].value;
          }
      }
      cout<<cost<<endl;
     }  
}

记住好吗!!!!!!!!

猜你喜欢

转载自blog.csdn.net/wnmxhAC/article/details/81273702