实验七 图及其应用

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值