【数据结构】图论基础整理

一、图的定义:点用边连起来

二、图的一些概念

1.有向图:图的边有方向,只能按箭头从一点走到另一点而不能逆着走。无向图:可以双向在两个点间走。

2.结点的度:无向图中与结点相连的边的数目;

结点的入度:有向图中以这个结点为终点的有向边的数目;

结点的出度:有向图中以这个结点为起点的有向边的数目;

3.权值:边的长度(或“费用”)。

4.连通:两个结点之间存在一条路径(可以是通过几个结点),则这两个点是连通的。

5.回路:起点和终点相同的路。

6.完全图:含有 n 个点,n * ( n - 1 ) / 2 条边的无向图,或 n * (n - 1) 条边的有向图。(即:每两个点都有边相连)

7.强连通分量:有向图中任意两点都连通的最大子图。单个点也是一个强连通分量。

 

三、图的存储

1.定义二维数组 int G[MAXN][MAXN]:

G[i][j]表示从i到j的边的权值。(无边时取值为无穷或0,可用0x7fffffff代替无穷大,0xaf代表无穷小)

注意:在memset(a,127,sizeof(a))中(a为double型数组),127表示的是1.38 * 10 ^ 306。

 

四、最短路径算法

1.Floyed算法(O(N^3))(可以处理负边权)

int dis[MAXN][MAXN];
//初始化:有边相连则dis[x][y]=这条边的权值。没有(直接的)边相连则dis[x][y]=0x7fffffff;
for(int k=1;k<=n;k++)//以k为“中转点”,必须放在最外一层循环上
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(dis[i][j]>dis[i][k]+dis[k][j])//如果通过另一个“中转点”会使两个点的距离更小,则更新它
                dis[i][j]=dis[i][k]+dis[k][j];
        }

2.Dijkstra算法(O(N^2))(不可以处理负边权):

dis数组:起点到某一点的距离;w数组:相连两点的直接路径的长度

【循环 i : 1 -> n】

(1)在没有被访问过的节点中选择一个节点i,使dis[i]最小。

(2)i确定是最短路径,这个结点标记已访问。

(3)【循环 j : 1 -> n】

    如果dis[i]+w[i][j]<dis[j](即具有更短的路)则:dis[j]=dis[i]+w[i][j].

【结束:dis[v]是起点到v的最短距离】

int dis[MAXN],w[MAXN][MAXN];//设起点为s,dis[v]表示s到v的最短路径,w[i][j]表示i到j之间的路径的费用。

bool vis[MAXN];//记录一个结点是否被访问
int s,v;//起点和终点

//初始化(假设w[i][j],s,v都已经输入完毕)
for(int i=1;i<=n;i++)
     dis[i]=0x7fffffff;
dis[s]=0;
pre[s]=0;
//算法主体
int min,k;//min记录从起点连接最短路径长度,k记录最短路径终点
for(int i=1;i<=n-1;i++)
{
    min=1e30;k=0;//初始化
    for(int j=1;j<=n;j++)//筛出最短边
    {
        if((!vis[j]) && (dis[j]<min))
        {
            min=dis[j];//更新最小值
            k=j;
        }
    }
    if(k==0)break;//无路可走了
    vis[k]=true;//这个最短路径的点确定了
    for(int j=1;j<=n;j++)//找寻其他最短路径
    {
        if(dis[k]+w[k][j]<dis[j])
            dis[j]=dis[k]+w[k][j];
    }
}
cout<<dis[v];//输出到v的最短距离

 

posted @ 2020-04-06 21:32  梦中霜雪梨花白  阅读(258)  评论(0编辑  收藏  举报