一、图的定义:点用边连起来
二、图的一些概念
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的最短距离