1.目的要求:
(1) 通过完成本实验,掌握图的两种基本的存储结构(邻接矩阵、邻接表),以及图的基本算法实现(建立、遍历),并能运用图结构分析和解决一些实际问题。
(2) 本实验训练的要点是:图的两种基本存储结构及各种操作的算法实现(建立、遍历、图的典型应用)。
2.实验内容:
(1) 建立图的邻接矩阵(或邻接表)存储表示,计算顶点的度(入度、出度),并实现图的深度优先或广度优先遍历。
(2) 编程实现最小生成树求解的Prim算法。
(3) 编程实现AOV网的拓扑排序。
(4) 编程求AOE网的关键路径。
(5) 编程实现单源点最短路径的Dijkstra算法。
注:(1)为必做题,(2)~(5)为选做题。
3.主要仪器设备及软件
(1) PC机
(2) Dev C++ ,Visual C++, VS2010等
代码
1)
//dfs
//bfs
/*
dfs
bfs
测试数据:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
结果:
dfs:
{01427}
{35}
{6}
bfs:
{01274}
{35}
{6}
0,outdegree:3
0,indegree:3
*/
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int map[10001][10001];
int dfs_visited[10001]={0};
int bfs_visited[10001]={0};
int V_num,E_num;
void dfs(int Vertex)
{
dfs_visited[Vertex]=1;
cout<<Vertex;
for(int i=0;i<V_num;i++){
if(!dfs_visited[i]&&map[Vertex][i]) dfs(i);
}
}
void bfs(int Vertex)
{
int tmp;
cout<<Vertex;
queue<int> q;
bfs_visited[Vertex]=1;
q.push(Vertex);
while(!q.empty()){
tmp=q.front();
q.pop();
for(int i=0;i<V_num;i++){
if(!bfs_visited[i]&&map[tmp][i]){
cout<<i;
q.push(i);
bfs_visited[i]=1;
}
}
}
}
void out_degree(int Vertex)
{
int cnt=0;
for(int i=0;i<V_num;i++){
if(map[Vertex][i]) cnt++;
}
printf("%d,outdegree:%d\n",Vertex,cnt);
}
void in_degree(int Vertex)
{
int cnt=0;
for(int i=0;i<V_num;i++){
if(map[i][Vertex]) cnt++;
}
printf("%d,indegree:%d\n",Vertex,cnt);
}
int main()
{
cin>>V_num>>E_num;
//图的初始化
for(int i=0;i<E_num;i++){
int v,l;
cin>>v>>l;
map[v][l]=map[l][v]=1;
}
cout<<"dfs:"<<endl;
for(int i=0;i<V_num;i++){
if(!dfs_visited[i]){
cout<<"{";
dfs(i);
cout<<"}"<<endl;
}
}
cout<<"bfs:"<<endl;
for(int i=0;i<V_num;i++){
if(!bfs_visited[i]){
cout<<"{";
bfs(i);
cout<<"}"<<endl;
}
}
out_degree(0);
in_degree(0);
return 0;
}
2)
//prim
/*
prim 让一棵小树长大
测试数据:
(从1-N编号)
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
结果:
12
*/
#include<iostream>
using namespace std;
#define Inf 0x3f3f3f3f
int map[10001][10001];
int dist[1001];
int parent[1001];
int V_num,E_num;
int find_min()
{
int index=-1;
int min=Inf;
//当前顶点从邻接的边找一条边最小的顶点
for(int i=1;i<=V_num;i++){
if(dist[i]!=0&&dist[i]<min){
min=dist[i];
index=i;
}
}
return index;
}
void prim(int S)
{
int cnt=1,e=0;
//初始化 parent dist
for(int i=1;i<=V_num;i++){
parent[i]=S;
dist[i]=map[S][i];
}
parent[S]=-1;//自己到自己的距离为-1
int v;
while(true){
v=find_min();
if(v==-1) break;//顶点全部找完
e+=dist[v];
cnt++;
dist[v]=0;//收录后 距离为0
for(int i=1;i<=V_num;i++){
if(dist[i]!=0&&map[v][i]<dist[i]){
dist[i]=map[v][i];
parent[i]=v;
}
}
}
if(cnt==V_num) cout<<e<<endl;//所顶点都被收录
else cout<<"-1"<<endl;//则不是最小生成树
}
int main()
{
cin>>V_num>>E_num;;
for(int i=1;i<=V_num;i++){
for(int j=1;j<=V_num;j++){
if(i==j) map[i][j]=map[j][i]=0;
else map[i][j]=map[j][i]=Inf;
}
}
for(int i=1;i<=E_num;i++){
int v1,v2,e1;
cin>>v1>>v2>>e1;
map[v1][v2]=map[v2][v1]=e1;
}
prim(1);
return 0;
}
3)
//拓扑排序
/*
拓扑排序
测试数据1:
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
结果1:
18
测试数据2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
结果:
Impossible
*/
#include<iostream>
#include<queue>
using namespace std;
#define Inf 0x3f3f3f3f
int map[10001][10001];
int V_num,E_num;
int Indegree[10001]={0};
int earliest[10001]={0};
queue<int> q;
int cnt=0;
int ECT;
int max(int arr[])
{
int max=arr[0];
for(int i=0;i<V_num;i++){
if(max<arr[i]){
max=arr[i];
}
}
return max;
}
int top_sort()
{
//计算顶点的入度
for(int i=0;i<V_num;i++){
for(int j=0;j<V_num;j++){
if(map[i][j]!=Inf) Indegree[j]++;
}
}
//入度为0的入队
for(int i=0;i<V_num;i++){
if(Indegree[i]==0){
q.push(i);
}
}
while(!q.empty()){
int tmp=q.front();
q.pop();
cnt++;
for(int i=0;i<V_num;i++){
if(map[tmp][i]!=Inf){
if(earliest[tmp]+map[tmp][i]>earliest[i]){
earliest[i]=earliest[tmp]+map[tmp][i];
}
if(--Indegree[i]==0){
q.push(i);
}
}
}
}
ECT=max(earliest);
if(cnt!=V_num) return 0;//cnt!=顶点数 说明存在回路
return 1;
}
int main()
{
cin>>V_num>>E_num;
for(int i=0;i<V_num;i++){
for(int j=0;j<V_num;j++){
map[i][j]=Inf;
}
}
for(int i=0;i<E_num;i++){
int v1,v2,e;
cin>>v1>>v2>>e;
map[v1][v2]=e;
}
if(!top_sort()) cout<<"Impossible"<<endl;
else cout<<ECT<<endl;
return 0;
}
5)
//Dijlstra单源最短路径
/*
Dijkstra
测试样例:
4 5 0 3
0 1 20
1 3 30
0 3 10
0 2 20
2 3 20
结果:
10
*/
#include<iostream>
#define Inf 0x3f3f3f
using namespace std;
int map[10001][10001];
int dist[10001]={0};
bool visited[10001]={false};
int V_num,E_num,V_source,V_Des;
void dijkstra(int Vertex)
{
dist[Vertex]=0;
visited[Vertex]=true;
for(int i=1;i<V_num;i++){
int min=Inf;//当前离源点最近的点
for(int j=0;j<V_num;j++){
if(!visited[j]&&dist[j]<min){
min=dist[j];
Vertex=j;
}
}
visited[Vertex]=true;
for(int j=0;j<V_num;j++){
if(!visited[j]&&(dist[j]>min+map[Vertex][j])){
dist[j]=map[Vertex][j]+min;
}
}
}
}
int main()
{
cin>>V_num>>E_num>>V_source>>V_Des;
//图的初始化
for(int i=0;i<V_num;i++){
for(int j=0;j<V_num;j++){
if(i==j) map[i][j]=map[j][i]=0;
else map[i][j]=map[j][i]=Inf;
}
}
for(int i=0;i<E_num;i++){
int v1,v2,e;
cin>>v1>>v2>>e;
map[v1][v2]=map[v2][v1]=e;
}
//初始化各个点到源点的距离
for(int i=0;i<V_num;i++) dist[i]=map[V_source][i];
dijkstra(V_source);
cout<<dist[V_Des];
return 0;
}
//Floyd 多源最短路径
/*
floyd 五行神奇代码!
测试数据:
6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80
结果:
4 70
*/
#include<iostream>
using namespace std;
#define Inf 0x3f3f3f3f
int map[10001][10001];
int V_num,E_num,dis;
//中点站
void Floyd()
{
for(int k=1;k<=V_num;k++){
for(int i=1;i<=V_num;i++){
for(int j=1;j<=V_num;j++){
if(map[i][j]>map[i][k]+map[k][j]){
map[i][j]=map[i][k]+map[k][j];
}
}
}
}
}
int main()
{
cin>>V_num>>E_num;
//初始化图 Inf 从1开始存
for(int i=1;i<=V_num;i++){
for(int j=1;j<=V_num;j++){
if(i==j) map[i][j]=map[j][i]=0;
else map[i][j]=map[j][i]=Inf;
}
}
//读入边
for(int i=1;i<=E_num;i++){
int V1,V2,E;
cin>>V1>>V2>>E;
map[V1][V2]=map[V2][V1]=E;
}
Floyd();
//index 到各点最短路径
//min 最小权值
int index=0;
int max;
int min=Inf;
for(int i=1;i<=V_num;i++){
max=0;
for(int j=1;j<=V_num;j++){
if(max<map[i][j]) max=map[i][j];
}
if(max<min){
min=max;
index=i;
}
}
if(index==0){
cout<<"0"<<endl;
}
else cout<<index<<" "<<min<<endl;
return 0;
}