图的基本术语
子图:类似于子集;
无向图和有向图:对于无向图若具有n(n-1)/2条边,则称之为无向完全图;对于有向图若具有n(n-1)条弧,则称之为有向完全图;
稀疏图和稠密图:边或弧(e<nlog2n)的图为稀疏图,反之为稠密图;
权和网:边带有权值,这种图叫做网;
邻接点和关联: 邻接是指顶点和顶点之间的关系,关联是指边和顶点之间的关系;
度、入度、出度:顶点v的度指和v相关联的边的数目;对于有向图,入度以v为头的弧的数目,出度以v为尾的弧的数目(<v1,v2>v1为弧尾(箭头指向自己),v2为弧头(箭头指向别人));
路径和路径长度:路径是A->B->...的一条路径,路径长度是一条路径经过的边或弧的数目;
回路或环:第一个顶点和最后一个顶点相同的路径称之为回路或环;
连通、连通图、连通分量(极大连通子图):连通;全连通的图;不可去如何一条边;
图的存储结构
邻接矩阵
//邻接矩阵
#define Maxint 32767
#define Mvnum 100
typedef struct{
int vexs[Mvnum];
int arcs[Mvnum][Mvnum];
int vexnum,arcnum;
}AG;
//邻接矩阵创建无向图
int Locvex(Ag &G,int v){
for(int i=0;i<G.vexnum;i++){
if(G.vexs[i]==v) return i;
}
return -1;
}
int createudn(AG &G){
cin>>G.vexnum>>G.arcnum;
for(int i=0;i<G.vexnum;i++) cin>>G.vexs[i];
for(int i=0;i<G.vexnum;i++)
for(int j=0;j<G.vexnum;j++)
G.arcs[i][j]=Maxint;
for(int k=0;k<G.arcnum;k++){
int v1,v2,w;cin>>v1>>v2>>w;
int i=locvex(G,v1);int j=locvex(G,v2);
G.arcs[i][j]=w;
G.arcs[j][i]=G.arcs[i][j];//删掉为有向图
}
}
邻接表
//邻接表
#define Mvnum 100
typedef struct Arcnode{
int adjvex;
struct Arcnode *nextarc;
int info;
}ArcNode;
typedef struct Vnode{
int data;
ArcNode *firstarc;
}VNode,AdjList[Mvnum];
typedef struct{
AdjList vertices;
int vexnum,arcnum;
}AlGraph;
//邻接表创建无向图
int create(AlGraph &G){
cin>>G.vexnum>>G.arcnum;
for(int i=0;i<G.vexnum;i++){
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
for(int k=0;k<G.arcnum;i++){
int v1,v2;cin>>v1>>v2;
int i=locatevex(G,v1);
int j=locatevex(G,v2);
p1=new ArcNode;
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstarc;G.vertices[i].firstarc=p1;
p2=new ArcNode;
p2->adjvex=i;
p2->nextarc=G.vertices[j].firstarc;G.vertices[j].firstarc=p2;
}
return 1;
}
最小生成树
普利姆算法
//(最小生成树)普利姆算法
struct{
int adjvex;
int lowcoat;
}closedge[Nvnum];
void Minstree_prim(AG &G,int u){
int k=Locvex(G,u);
for(int j=0;j<G.vexnum;j++)
if(j!=k) closedge[j]={u,G.arcs[k][j]};
closedge[k].lowcoat=0;
for(int i=1;i<G.vexnum;i++){
int K=min(closedge);
int u0=closedge[K].adjvex;
int v0=G.vexs[k];
cout<<u0<<"--"<<v0;
closedge[k].lowcoat=0;
for(int j=0;j<G.vexnum;j++)
if(G.arcs[k][j]<closedge[j].lowcoat)
closedge[j]={G.vexs[K],G.arcs[K][j]};
}
}
克鲁斯卡尔算法
#include <bits/stdc++.h>
using namespace std;
#define Maxint 32767
#define Mvnum 100
//邻接矩阵
typedef struct{
int vexs[Mvnum];
int arcs[Mvnum][Mvnum];
int vexnum,arcnum;
}AG;
typedef struct Edge{
int head;
int tail;
int lowcost;
}Edge;
//邻接矩阵创建无向图
int Locvex(AG &G,int v){
for(int i=0;i<G.vexnum;i++){
if(G.vexs[i]==v) return i;
}
return -1;
}
int createudn(AG &G,Edge edge[Mvnum]){
cin>>G.vexnum>>G.arcnum;
for(int i=0;i<G.vexnum;i++) cin>>G.vexs[i];
for(int i=0;i<G.vexnum;i++)
for(int j=0;j<G.vexnum;j++)
G.arcs[i][j]=Maxint;
for(int k=0;k<G.arcnum;k++){
int v1,v2,w;cin>>v1>>v2>>w;
int i=Locvex(G,v1);int j=Locvex(G,v2);
G.arcs[i][j]=w;
G.arcs[j][i]=G.arcs[i][j];//删掉为有向图
edge[i].head=v1;
edge[i].tail=v2;
edge[i].lowcost=w;
}
}
//(最小生成树)克鲁斯卡尔算法
int vexset[Mvnum];
void MinsTree_kruskal(AG G,Edge edge[Mvnum]){
sort(edge,edge+G.arcnum,[](const Edge &x,const Edge &y){
return x.lowcost<y.lowcost;
});
for(int i=0;i<G.vexnum;i++) vexset[i]=i;
for(int i=0;i<G.arcnum;i++){
int v1=Locvex(G,edge[i].head);
int v2=Locvex(G,edge[i].tail);
if(vexset[v1]!=vexset[v2]){
cout<<edge[i].head<<"--"<<edge[i].tail<<" :"<<edge[i].lowcost<<"\n";
for(int j=0;j<G.vexnum;j++)
if(vexset[j]==vexset[v2]) vexset[j]=vexset[v1];
}
}
}
int main(){
AG G;
Edge edge[Mvnum];
createudn(G,edge);
MinsTree_kruskal(G,edge);
return 0;
}
最短路径问题
迪杰斯特拉算法
//(最短路径)迪杰斯特拉算法
int s[Mvnum],cost[Mvnum],path[Mvnum];
void short_dij(AG &G,int v0){
int n=G.vexnum;
for(int v=0;v<n;v++){
s[v]=0;
cost[v]=G.arcs[v0][v];
if(cost[v]<Maxint) path[v]=v0;
else path[v]=-1;
}
s[v0]=1;
for(int i=1;i<n;i++){
min=Maxint;
for(int w=0;w<n;w++)
if(s[w]==0&&cost[w]<min){
v=w;min=cost[w];
}
s[v]=1;
for(int w=0;w<n;w++){
if(s[v]==0&&(cost[v]+G.arcs[v][w]<cost[w])){
cost[w]=cost[v]+G.arcs[v][w];
path[w]=v;
}
}
}
}