一、 实验目的和要求
1.掌握在图的邻接矩阵和邻接表存储结构实现图的基本运算的算法。学习使用图算法解决应用问题的方法。
(1). 验证教材中关于在邻接矩阵和邻接表两种不同存储结构上实现图的基本运算的算法
(2)在邻接矩阵和邻接表存储结构上实现图的深度和宽度优先遍历算法。
(3)在两种储存结构上面分别实现Dijkstra、prim、Floyd算法
2.飞机最少换乘次数问题。
程序一:邻接矩阵表示的图的运算
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cstring>
#define INF 1e8
#define Size 200
using namespace std;
template<class T>
class MGraph
{
public:
MGraph(int mSize);
~MGraph();
bool Insert(int u,int v,int w);
bool Remove(int u,int v);
bool Exist(int u,int v)const;
void DFS();
void BFS();
void Dijkstra(int v,T *d,int *path);
void Floyd(int d[][Size],int path[][Size]);
void prim(int k,int *nearest,T* lowcost);
protected:
int Choose(int *d,bool *s);
void DFS(int v,bool *visited);
void BFS(int v,bool *visited);
T **a;
int n,e;
};
template<class T>
MGraph<T>::MGraph(int mSize)
{
n=mSize;e=0;
a=new T*[n];
for(int i=0;i<n;i++)
{
a[i]=new T[n];
for(int j=0;j<n;j++)
{
a[i][j]=INF;
}
a[i][i]=0;
}
}
template<class T>
MGraph<T>::~MGraph()
{
for(int i=0;i<n;i++)
{
delete []a[i];
}
delete []a;
}
template<class T>
bool MGraph<T>::Exist(int u,int v)const
{
if(u<0||v<0||u>n-1||v>n-1||u==v||a[u][v]==INF) return false;
return true;
}
template<class T>
bool MGraph<T>::Insert(int u,int v,int w)
{
if(u<0||v<0||u>n-1||v>n-1||u==v ) return false;
if(a[u][v]!=INF) return false;
a[u][v]=w;
e++;
return true;
}
template<class T>
bool MGraph<T>::Remove(int u,int v)
{
if(u<0||v<0||u>n-1||v>n-1||u==v)return false;
if(a[u][v]==INF)return false;
a[u][v]=INF;
e--;
return true;
}
template<class T>
void MGraph<T>::DFS()
{
int i;
bool *visited=new bool[n];
for(i=0;i<n;i++)
visited[i]=false;
for(i=0;i<n;i++)
{
if(visited[i]==false)
{
DFS(i,visited);
}
}
cout<<endl;
delete []visited;
}
template<class T>
void MGraph<T>::DFS(int v,bool *visited)
{
visited[v]=true;
printf(" %d ",v);
for(int u=0;u<n;u++)
{
if(a[v][u]!=INF && visited[u]== false)
{
DFS(u,visited);
}
}
}
template<class T>
void MGraph<T>::BFS()
{
int i;
bool *visited=new bool[n];
for(i=0;i<n;i++)
visited[i]=false;
for(i=0;i<n;i++)
{
if(visited[i]==false)
{
BFS(i,visited);
}
}
cout<<endl;
delete []visited;
}
template<class T>
void MGraph<T>::BFS(int v,bool *visited)
{
queue<int> Q;
visited[v]=true;
Q.push(v);
while(!Q.empty())
{
v=Q.front();
Q.pop();
cout<<v<<" ";
for(int i=0;i<n;i++)
{
if(visited[i]==false&&a[v][i]!=INF)
{
visited[i]=true;
Q.push(i);
}
}
}
}
template <class T>
void MGraph<T>::prim(int k,int *nearest,T* lowcost)
{
bool *mark=new bool[n];
if(k<0||k>n-1)
{
printf("out of bounds\n");
return;
}
for(int i=0;i<n;i++)
{
nearest[i]=-1;
lowcost[i]=INF;
mark[i]=false;
}
lowcost[k]=0;
nearest[k]=k;
mark[k]=true;
int cnt=n-1;
while(cnt--)
{
for(int i=0;i<n;i++)
{
if(a[k][i]!=INF)
{
if((!mark[i])&&(lowcost[i]>a[k][i]))
{
lowcost[i]=a[k][i];
nearest[i]=k;
}
}
}
T minn=INF;
for(int j=0;j<n;j++)
{
if((!mark[j])&&(lowcost[j]<minn))
{
minn=lowcost[j];
k=j;
}
}
mark[k]=true;
}
}
template<class T>
int MGraph<T>::Choose(int *d,bool *s)
{
int i,minpos;
T min;
min=INF;
minpos=-1;
for(i=0;i<n;i++)
{
if(d[i]<=min&&!s[i])
{
min=d[i];
minpos=i;
}
}
return minpos;
}
template<class T>
void MGraph<T>::Dijkstra(int v,T *d,int *path)
{
int i,k,w;
if(v<0||v>n-1)
{
cout<<"out of bounds!"<<endl;
return;
}
bool *s=new bool[n];
for(i=0;i<n;i++)
{
s[i]=false;
d[i]=a[v][i];
if(i!=v&&d[i]<INF)
path[i]=v;
else path[i]=-1;
}
s[v]=true;
d[v]=0;
for(i=1;i<n;i++)
{
printf("\n%d:d[]\n",i);
for(int k=0;k<n;k++)
{
printf("%d ",d[k]);
}
printf("\npath\n");
for(int k=0;k<n;k++)
{
printf("%d ",path[k]);
}
k=Choose(d,s);
s[k]=true;
for(w=0;w<n;w++)
{
if(!s[w]&&d[k]+a[k][w]<d[w])
{
d[w]=d[k]+a[k][w];
path[w]=k;
}
}
}
}
template<class T>
void MGraph<T>::Floyd(int d[][Size],int path[][Size])
{
int i,j,k;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
d[i][j]=a[i][j];
if(i!=j&&a[i][j]<INF)
{
path[i][j]=i;
}
else
{
path[i][j]=-1;
}
}
}
printf("初始d和path的值:\n");
printf("数组d:\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(d[i][j]==INF)
{
printf(" INF");
}
else
{
printf("%5d",d[i][j]);
}
}
printf("\n");
}
printf("数组path:\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",path[i][j]);
}
printf("\n");
}
for(k=0;k<n;k++)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(d[i][k]+d[k][j]<d[i][j])
{
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[k][j];
}
}
}
printf("k= %d \n",k);
printf("数组d:\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(d[i][j]==INF)
{
printf(" INF");
}
else
{
printf("%5d",d[i][j]);
}
}
printf("\n");
}
printf("数组path:\n");
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%5d",path[i][j]);
}
printf("\n");
}
}
}
int main()
{
int i,j;
int n;
printf("请输入图的顶点数\n");
scanf("%d",&n);
printf("图的顶点为 0 ~ %d\n",n-1);
MGraph<int> M(n);
printf("图是无向图还是有向图? 1.无向图 2.有向图 \n");
int choice;
scanf("%d",&choice);
if(choice!=1&&choice!=2)
{
printf("输入有误\n");
return 0;
}
if(choice==1)
{
printf("请输入无向边的个数:\n");
}
else
{
printf("请输入有向边的个数:\n");
}
int m;
scanf("%d",&m);
printf("请输入 %d 条边\n",m);
int x,y,w;
if(choice==1)
{
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&w);
M.Insert(x,y,w);
M.Insert(y,x,w);
}
}
else
{
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&w);
M.Insert(x,y,w);
}
}
printf("\n深度优先遍历为:\n");
M.DFS();
printf("宽度优先遍历为:\n");
M.BFS();
printf("Prim 算法测试\n");
int nearest[Size];
int lowcost[Size];
int flag=0;
M.prim(0,nearest,lowcost);
for(i=0;i<n;i++)
{
if(lowcost[i]==INF)
{
flag=1;
}
}
if(flag==0)
{
printf("最小生成树边集为:\n");
for(i=0;i<n;i++)
{
printf("(%d,%d,%d) ",nearest[i],i,lowcost[i]);
}
printf("\n\n");
}
else
{
printf("这个图不是一个连通图:\n");
}
int d[Size];
int path[Size];
int v,s;
printf("\nDijkstra单源最短路测试\n请输入起点和终点坐标:\n");
scanf("%d%d",&v,&s);
M.Dijkstra(v,d,path);
int record[Size];
if(d[s]==INF)
{
printf("无法从 %d 到达 %d\n",v,s);
}
else
{
printf("最短路径长度是 %d \n",d[s]);
i=s,j=1;
record[0]=s;
while(path[i]!=v)
{
record[j++]=path[i];
i=path[i];
}
record[j++]=v;
reverse(record,record+j);
printf("路径为:\n");
for(i=0;i<j;i++)
{
if(i==0) printf("%d",record[i]);
else printf(" ->%d",record[i]);
}
printf("\n\n");
}
printf("Floyd 任意两点之间的最短路 算法测试\n");
int dd[Size][Size];
int ppath[Size][Size];
M.Floyd(dd,ppath);
printf("请输入 起点和终点 ,输入 0 0 停止:\n");
while(scanf("%d%d",&v,&s)==2)
{
if(v==0&&s==0) break;
if(dd[v][s]==INF)
{
printf("无法从 %d 到达 %d \n",v,s);
}
else
{
printf("最短路长度是: %d \n",dd[v][s]);
memset(record,0,sizeof(record));
j=0;
while(s!=v)
{
record[j++]=s;
s=ppath[v][s];
}
record[j++]=s;
reverse(record,record+j);
printf("路径为:\n");
for(i=0;i<j;i++)
{
if(i==0) printf("%d",record[i]);
else printf("->%d",record[i]);
}
}
printf("\nFloyd 请输入 起点和终点 ,输入 0 0 停止:\n");
}
return 0;
}
程序二:邻接表表示的图的基本运算
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#define INF 1e8
#define Size 200
using namespace std;
struct edge //边的结构体
{
int to;
int cost;
edge(int x,int y)
{
to=x;
cost=y;
}
};
template<class T>
class LGraph
{
private:
vector<edge> *M;
int n;
int e;
void DFS(int u,bool *vis);
void BFS(int v,bool *vis);
public:
LGraph(int mSize);
~LGraph();
bool Insert(int u,int v,int w);
bool Exist(int u,int v);
bool Remove(int u,int v);
void Dijkstra(int v,T *d,int *path);
void prim(int k,int *nearest,T* lowcost);
void Floyd(int d[][Size],int path[][Size]);
void DFS();
void BFS();
};
template<class T>
LGraph<T>::LGraph(int mSize)
{
M=new vector<edge>[mSize];
n=mSize;
e=0;
}
template<class T>
LGraph<T>::~LGraph()
{
int i;
for(i=0;i<n;i++)
{
M[i].clear();
}
delete []M;
}
template<class T>
bool LGraph<T>::Insert(int u,int v,int w)
{
int i;
if(u<0||u<0||v>n-1||u>n-1) return false;
for(i=0;i<M[u].size();i++)
{
if(M[u][i].to==v)
{
return false;
}
}
edge tmp(v,w);
M[u].push_back(tmp);
e++;
return true;
}
template<class T>
bool LGraph<T>::Exist(int u,int v)
{
int i;
if(u<0||v<0||u>n-1||v>n-1) return false;
for(i=0;i<M[u].size();i++)
{
if(M[u][i].to==v)
{
return true;
}
}
return false;
}
template<class T>
bool LGraph<T>::Remove(int u,int v)
{
int i;
if(u<0||v<0||u>n-1||v>n-1) return false;
for(i=0;i<M[u].size();i++)
{
if(M[u][i].to==v)
{
M[u].erase(M[u].begin()+i);
return true;
}
}
return false;
}
int cmp(edge a,edge b)
{
return a.to<b.to;
}
template<class T>
void LGraph<T>::DFS()
{
for(int i=0;i<n;i++)
{
sort(M[i].begin(),M[i].end(),cmp);
}
int i;
bool *vis=new bool[n+1];
for(i=0;i<n;i++)
{
vis[i]=false;
}
for(i=0;i<n;i++)
{
if(vis[i]==false)
{
DFS(i,vis);
}
}
delete []vis;
cout<<endl;
}
template<class T>
void LGraph<T>::DFS(int v,bool *vis)
{
vis[v]=true;
printf("%d ",v);
int i;
for(i=0;i<M[v].size();i++)
{
int t=M[v][i].to;
if(vis[t]==false)
{
DFS(t,vis);
}
}
}
template<class T>
void LGraph<T>::BFS()
{
int i;
bool *vi=new bool[n];
for(i=0;i<n;i++)
{
vi[i]=false;
}
for(i=0;i<n;i++)
{
if(vi[i]==false)
{
BFS(i,vi);
}
}
cout<<endl;
delete []vi;
}
template<class T>
void LGraph<T>::BFS(int v,bool *vi)
{
int i;
vi[v]=true;
queue<int> Q;
Q.push(v);
while(!Q.empty())
{
v=Q.front();
printf("%d ",v);
Q.pop();
for(i=0;i<M[v].size();i++)
{
int t=M[v][i].to;
if(vi[t]==false)
{
Q.push(t);
vi[t]=true;
}
}
}
}
template<class T>
void LGraph<T>::Dijkstra(int v,T *d,int *path)
{
int i;
bool *s=new bool[n];
for(i=0;i<n;i++)
{
d[i]=INF;
path[i]=-1;
s[i]=false;
}
for(i=0;i<M[v].size();i++)
{
int t=M[v][i].to;
d[t]=M[v][i].cost;
path[t]=v;
}
s[v]=true;
d[v]=0;
for(i=1;i<n;i++)
{
int index=-1;
int min=INF;
for(int j=0;j<n;j++)
{
if(s[j]==false && d[j]<=min)
{
min=d[j];
index=j;
}
}
s[index]=true;
for(int k=0;k<M[index].size();k++)
{
int t=M[index][k].to;
if(d[index]+M[index][k].cost<d[t]&&s[t]==false)
{
d[t]=d[index]+M[index][k].cost;
path[t]=index;
}
}
}
delete []s;
}
template<class T>
void LGraph<T>::prim(int k,int *nearest,T* lowcost)
{
bool *mark=new bool[n+1];
for(int i=0;i<n;i++)
{
nearest[i]=-1;
mark[i]=false;
lowcost[i]=INF;
}
mark[k]=true;
lowcost[k]=0;
nearest[k]=k;
for(int i=1;i<n;i++)
{
for(int j=0;j<M[k].size();j++)
{
int t=M[k][j].to;
if(lowcost[t]>M[k][j].cost&&!(mark[t]))
{
lowcost[t]=M[k][j].cost;
nearest[t]=k;
}
}
int min=INF;
for(int j=0;j<n;j++)
{
if(!mark[j] && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
}
mark[k]=true;
}
delete []mark;
}
template <class T>
void LGraph<T>::Floyd(int d[Size][Size],int path[Size][Size])
{
for(int i=0;i<Size;i++)
{
for(int j=0;j<Size;j++)
{
d[i][j]=INF;
path[i][j]=-1;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<M[i].size();j++)
{
int t=M[i][j].to;
d[i][t]=M[i][j].cost;
path[i][t]=i;
}
}
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(d[i][k]+d[k][j]<d[i][j])
{
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[k][j];
}
}
}
}
}
int main()
{
int n;
printf("请输入顶点数:\n");
scanf("%d",&n);
LGraph<int> G(n);
printf("请输入构建有向图还是无向图? 1.无向图 2.有向图\n");
int choice;
cin>>choice;
if(choice!=1&&choice!=2)
{
printf("输入有误,请重新输入\n");
return 0;
}
else if(choice==2)
{
printf("请输入有向边的个数\n",n);
int m;
cin>>m;
printf("请输入%d条有向边\n",n);
for(int i=0;i<m;i++)
{
int x,y,z;
cin>>x>>y>>z;
G.Insert(x,y,z);
}
}
else
{
printf("请输入无向边的个数\n");
int m;
cin>>m;
printf("请输入 %d 条无向边\n");
for(int i=0;i<m;i++)
{
int x,y,z;
cin>>x>>y>>z;
G.Insert(x,y,z);
G.Insert(y,x,z);
}
}
printf("深度优先遍历:\n");
G.DFS();
printf("宽度优先遍历:\n");
G.BFS();
int *lowcost=new int[n+1];
int *nearest=new int[n+1];
G.prim(0,nearest,lowcost);
printf("prim 最小生成树测试 :\n");
int flag=0;
for(int i=0;i<n;i++)
{
if(lowcost[i]==INF)
{
flag=1;
}
}
if(flag==0)
{
for(int i=0;i<n;i++)
{
printf("%d %d %d\n",nearest[i],i,lowcost[i]);
}
}
else
{
printf("这个图不是一个连通图:\n");
}
printf("\n\n");
delete []nearest;
delete []lowcost;
printf("Dijkstra单源最短路测试:\n");
printf("请输入起点和终点:\n");
printf("起点:");
int x;
cin>>x;
printf("终点:");
int y;
cin>>y;
int *path=new int[n+1];
int *d=new int[n+1];
G.Dijkstra(x,d,path);
if(d[y]==INF)
{
printf("没有路能从 %d 到达 %d \n",x,y);
}
else
{
printf("最短路径长度为: %d\n",d[y]);
int *record=new int[n+1];
int j=0;
while(y!=x)
{
record[j++]=y;
y=path[y];
}
record[j++]=x;
reverse(record,record+j);
printf("路径为:\n");
for(int i=0;i<j;i++)
{
if(i==0) printf("%d",record[i]);
else printf("->%d",record[i]);
}
printf("\n\n");
delete []record;
}
delete []d;
delete []path;
int dd[Size][Size];
int ppath[Size][Size];
printf("Floyd 算法所有顶点最短路测试:\n");
G.Floyd(dd,ppath);
printf("\nFloyd 请输入 起点和终点 ,输入 0 0 停止:\n");
int v,s;
while(scanf("%d%d",&v,&s)==2)
{
int record[Size];
if(v==0&&s==0) break;
if(dd[v][s]==INF)
{
printf("无法从 %d 到达 %d \n",v,s);
}
else
{
printf("最短路长度是: %d \n",dd[v][s]);
memset(record,0,sizeof(record));
int j=0;
while(s!=v)
{
record[j++]=s;
s=ppath[v][s];
}
record[j++]=s;
reverse(record,record+j);
printf("路径为:\n");
for(int i=0;i<j;i++)
{
if(i==0) printf("%d",record[i]);
else printf("->%d",record[i]);
}
}
printf("\nFloyd 请输入 起点和终点 ,输入 0 0 停止:\n");
}
return 0;
}
程序三:飞机换乘问题
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cstring>
#define INF 1e8
#define Size 200
using namespace std;
template<class T>
class MGraph
{
public:
MGraph(int mSize);
~MGraph();
bool Insert(int u,int v);
void Dijkstra(int v,T *d,int *path);
protected:
int Choose(int *d,bool *s);
T **a;
int n,e;
};
template<class T>
MGraph<T>::MGraph(int mSize)
{
n=mSize;e=0;
a=new T*[n];
for(int i=0;i<n;i++)
{
a[i]=new T[n];
for(int j=0;j<n;j++)
{
a[i][j]=INF;
}
a[i][i]=0;
}
}
template<class T>
MGraph<T>::~MGraph()
{
for(int i=0;i<n;i++)
{
delete []a[i];
}
delete []a;
}
template<class T>
bool MGraph<T>::Insert(int u,int v)
{
if(u<0||v<0||u>n-1||v>n-1||u==v ) return false;
if(a[u][v]!=INF) return false;
a[u][v]=1;
e++;
return true;
}
template<class T>
int MGraph<T>::Choose(int *d,bool *s)
{
int i,minpos;
T min;
min=INF;
minpos=-1;
for(i=0;i<n;i++)
{
if(d[i]<=min&&!s[i])
{
min=d[i];
minpos=i;
}
}
return minpos;
}
template<class T>
void MGraph<T>::Dijkstra(int v,T *d,int *path)
{
int i,k,w;
if(v<0||v>n-1)
{
cout<<"out of bounds!"<<endl;
return;
}
bool *s=new bool[n];
for(i=0;i<n;i++)
{
s[i]=false;
d[i]=a[v][i];
if(i!=v&&d[i]<INF)
path[i]=v;
else path[i]=-1;
}
s[v]=true;
d[v]=0;
for(i=1;i<n;i++)
{
k=Choose(d,s);
s[k]=true;
for(w=0;w<n;w++)
{
if(!s[w]&&d[k]+a[k][w]<d[w])
{
d[w]=d[k]+a[k][w];
path[w]=k;
}
}
}
}
int main()
{
int n;
printf("请输入城市个数:");
cin>>n;
MGraph<int> G(n);
int m;
printf("请输入航线个数:");
cin>>m;
printf("请输入m条航线的起点和终点:\n");
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
G.Insert(x,y);
}
printf("请输入你出发地和目的地:\n");
int x,y;
printf("出发地:");
cin>>x;
printf("目的地:");
cin>>y;
int *d=new int[n];
int *path=new int[n];
G.Dijkstra(x,d,path);
if(d[y]==INF)
{
printf("没有从 %d 到 %d的换成方案\n",x,y);
}
else
{
printf("最少换乘次数为: %d\n",d[y]);
int *record=new int[n+1];
int j=0;
while(y!=x)
{
record[j++]=y;
y=path[y];
}
record[j++]=x;
reverse(record,record+j);
printf("换乘方案为:\n");
for(int i=0;i<j;i++)
{
if(i==0) printf("%d",record[i]);
else printf("->%d",record[i]);
}
printf("\n\n");
delete []record;
}
delete []d;
delete []path;
return 0;
}