1.输入指定的边数和顶点数建立图,并输出深度优先遍历和广度优先遍历的结果。
1)问题描述:在主程序中设计一个简单的菜单,分别调用相应的函数功能:
1…图的建立
2…深度优先遍历图
3…广度优先遍历图
0…结束
2)实验要求:在程序中定义下述函数,并实现要求的函数功能:
CreateGraph(): 按从键盘的数据建立图
DFSGrahp():深度优先遍历图
BFSGrahp():广度优先遍历图
3)实验提示:
图的存储可采用邻接表或邻接矩阵;
图存储数据类型定义 (邻接表存储)
# define MAX_VERTEX_NUM 8 //顶点最大个数
typedef struct ArcNode
{ int adjvex;
struct ArcNode *nextarc;
int weight; //边的权
}ArcNode; //表结点
# define VertexType int //顶点元素类型
typedef struct VNode
{ int degree,indegree; //顶点的度,入度
VertexType data;
ArcNode *firstarc;
}Vnode /*头结点*/, AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList vertices;
int vexnum,arcnum;//顶点的实际数,边的实际数
}ALGraph;
4)注意问题:
注意理解各算法实现时所采用的存储结构。
注意区别正、逆邻接。
#include<iostream>
using namespace std;
#include<cstdlib>
#include<queue> //c++的队列库函数
#include<algorithm>
# define MAX_VERTEX_NUM 8 //顶点最大个数
typedef struct ArcNode{
int adjvex;
ArcNode *nextarc;
}ArcNode;
typedef struct VNode{
int data; //int 类型
ArcNode *firstarc;
}Vnode, AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList vertex;
int vexnum,arcnum; //顶点的实际数,边的实际数
}Graph;
void CreateGraph(Graph &G){
ArcNode* s;
int i,j;
int k,d;
int n = G.vexnum;
int e = G.arcnum;
for(i=1; i<=n; i++){ //n为顶点数、e为边数
G.vertex[i].data = i;
G.vertex[i].firstarc = NULL;
}
for(i=1; i<=e; i++){
// 输入边
scanf("%d%d",&k,&d);
s = (ArcNode*)malloc(sizeof(ArcNode));
s->adjvex = d;
s->nextarc = G.vertex[k].firstarc;
G.vertex[k].firstarc = s;
s = (ArcNode*)malloc(sizeof(ArcNode));
s->adjvex = k;
s->nextarc = G.vertex[d].firstarc;
G.vertex[d].firstarc = s;
}
for(i=1;i<=n;i++){
int count=0;
int paixu[100] = {0};
ArcNode* r;
r = (ArcNode*)malloc(sizeof(ArcNode));
r = G.vertex[i].firstarc;
while(r!=NULL){
paixu[count] = r->adjvex;
count++;
r = r->nextarc;
}
sort(paixu,paixu+100);
r = G.vertex[i].firstarc;
count =100-count;
while(r!=NULL){
r->adjvex = paixu[count];
count++;
r = r->nextarc;
}
}
}
int flag[100] = {0};
int con=1;
void DFS(Graph G,int v){
if(con < G.vexnum){
cout<<G.vertex[v].data<<" ";
con++;
}
else{
cout<<G.vertex[v].data;
}
ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
p = G.vertex[v].firstarc;
flag[v] = 1;
while(p){
if(!flag[p->adjvex]){
DFS(G,p->adjvex);
}
p = p->nextarc;
}
}
int flag1[100] = {0};
int con1 = 1;
void BFS(Graph G,int v){
queue <int> Q;
cout<<G.vertex[v].data<<" ";
con1++;
ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
flag1[v] = 1;
Q.push(v);
while(!Q.empty()){
v = Q.front();
Q.pop();
p = G.vertex[v].firstarc;
while(p){
if(!flag1[p->adjvex]){
if(con1 < G.vexnum){
cout<<G.vertex[p->adjvex].data<<" ";
con1++;
}
else{
cout<<G.vertex[p->adjvex].data;
}
flag1[p->adjvex] = 1;
Q.push(p->adjvex);
}
p = p->nextarc;
}
}
}
int main(){
int T;
Graph G;
cout<<"1...图的建立"<<endl;
cout<<"2...深度优先遍历图"<<endl;
cout<<"3...广度优先遍历图"<<endl;
cout<<"0...结束"<<endl;
cout<<endl;
scanf("%d",&T);
while(T != 0){
if(T == 1){
cout<<"请输入图的顶点数和边数"<<endl;
scanf("%d%d",&G.vexnum,&G.arcnum); // 顶点数 边数
CreateGraph(G); //建立图
cout<<"建图成功"<<endl;
}
else if(T == 2){
cout<<"深度优先遍历结果为:"<<endl;
DFS(G,1); //深度优先遍历图
cout<<endl;
}
else if(T == 3){
cout<<"广度优先遍历结果为:"<<endl;
BFS(G,1); //广度优先遍历图
cout<<endl;
}
scanf("%d",&T);
}
return 0;
}
2. 教学计划编制问题
1)问题描述:软件专业的学生要学习一系列课程,其中有些课程必须在其先修课完成后才能学习。
2)实验要求:假设每门课程的学习时间为一个学期,试为该专业的学生设计教学计划,使他们能在最短时间内修完专业要求的全部课程。
3) 实现提示:
- 以顶点代表课程,弧代表课程的先后修关系,按课程先后关系建立有向无环图。
- 利用拓扑排序实现。
#include<iostream>
using namespace std;
#include<cstdlib>
#include<stack> //c++的栈库函数
#include<algorithm>
# define MAX_VERTEX_NUM 8 //顶点最大个数
typedef struct ArcNode{
int adjvex;
ArcNode *nextarc;
}ArcNode; //表结点
#define VertexType int //顶点元素类型
typedef struct VNode{
int degree,indegree; //顶点的度,入度
int data; //int 类型
ArcNode *firstarc;
}Vnode, AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList vertex;
int vexnum,arcnum; //顶点的实际数,边的实际数
}Graph;
void CreateGraph(Graph &G){
ArcNode* s;
int i,j;
int k,d;
int n = G.vexnum;
int e = G.arcnum;
for(i=1; i<=n; i++){ //n为顶点数、e为边数
G.vertex[i].data = i;
G.vertex[i].firstarc = NULL;
G.vertex[i].indegree = 0;
}
cout<<"请输入各边"<<endl;
for(i=1; i<=e; i++){
scanf("%d%d",&k,&d);
s = (ArcNode*)malloc(sizeof(ArcNode));
s->adjvex = d;
G.vertex[d].indegree++;
s->nextarc = G.vertex[k].firstarc;
G.vertex[k].firstarc = s;
}
for(i=1;i<=n;i++){
int count=0;
int paixu[100] = {0};
ArcNode* r;
r = (ArcNode*)malloc(sizeof(ArcNode));
r = G.vertex[i].firstarc;
while(r!=NULL){
paixu[count] = r->adjvex;
count++;
r = r->nextarc;
}
sort(paixu,paixu+100);
r = G.vertex[i].firstarc;
count =100-count;
while(r!=NULL){
r->adjvex = paixu[count];
count++;
r = r->nextarc;
}
}
}
int TS(Graph G){
int i,k,tmp,count=1;
stack<int> s;
ArcNode *p;
for(i=G.vexnum;i>0;i--){
if( G.vertex[i].indegree == 0){
s.push(i);
}
}
cout<<endl<<"结果为:"<<endl;
while(!s.empty()){
int tm[100]={0};
int con=0;
while(!s.empty()){
tm[con] = s.top();
con++;
s.pop();
}
sort(tm,tm+100);
int con1 = con;
while(con){
s.push(tm[100-con1+con-1]);
con--;
}
tmp = s.top();
s.pop();
if(count<G.vexnum){
cout<<G.vertex[tmp].data<<" ";
count++;
}
else{
cout<<G.vertex[tmp].data;
}
for(p = G.vertex[tmp].firstarc; p; p=p->nextarc){
k = p->adjvex;
if(!(--G.vertex[k].indegree)){
s.push(k);
}
}
}
}
int main(){
Graph G;
cout<<"请输入顶点数和边数:"<<endl;
scanf("%d%d",&G.vexnum,&G.arcnum); // 顶点数 边数
CreateGraph(G); //建立图
TS(G);
return 0;
}
3.给定实际背景,解决最短路径问题
1)问题描述:假设以一个带权有向图表示某一区域的公交线路网,图中顶点代表一些区域中的重要场所,弧代表已有的公交线路,弧上的权表示该线路上的票价(或搭乘所需时间),试设计一个交通指南系统,指导前来咨询者以最低的票价或最少的时间从区域中的某一场所到达另一场所。
2)实验要求:利用Dijkstra算法求最低的票价
3) 实现提示:
- 该问题可以归结为一个求带权有向图中顶点间最短路径的问题。
- 建立以票价为权的有向图,再利用Dijkstra算法求最短路径及其路径长度。
#include<iostream>
using namespace std;
typedef struct Arc{
int quan;
}AdjMatrix[500][500]; //矩阵
typedef struct Graph{
int vertex[1000];
AdjMatrix arcs;
int vexnum,arcnum;
};
int main(){
int n,m;
Graph G;
cout<<"请输入顶点数和边数:"<<endl;
cin>>n>>m;
int i,j;
for(i=1;i<=n;i++){ //初始化矩阵
for(j=1;j<=n;j++){
G.arcs[i][j].quan = 99999;
}
}
int m1 = m;
int a,b,c;
int P;
cout<<"请输入边信息:"<<endl;
while(m1--){ //赋权值
cin>>a>>b>>c;
G.arcs[a][b].quan = c;
}
int q[1000];
for(i=0;i<=1000;i++){
q[i] = 99999;
}
int n1 = n-1;
int nowi = 1, nowq = 0,nowj = 1;
int z = 9999;
while(n1--){
int min = 99999;
for(j=1;j<=n;j++){
if(nowi != j){
if(G.arcs[nowi][j].quan < q[j]){
q[j] = G.arcs[nowi][j].quan;
if(nowj == j){
q[j] += nowq;
}
}
if(G.arcs[nowi][j].quan < min){
min = G.arcs[nowi][j].quan;
}
}
}
for(j=1;j<=n;j++){
if(min == q[j]){
nowj = j;
}
}
nowq = nowq + min;
q[nowj] = nowq;
int min1 = 99999;
for(i=1;i<=n;i++){
if(q[i]<=min1){
min1 = q[i];
nowi = i;
}
}
nowq = min1;
if(nowi==n && nowq<z){
z = nowq;
}
for(j=1;j<=n;j++){
if(min1 == q[j]){
q[j] = 99999;
}
}
}
cout<<"第1个节点到第n个节点的最短路径:"<<endl;
cout<<z;
return 0;
}
4.利用最小生成树算法解决通信网的总造价最低问题
1)问题描述:若在n个城市之间建通信网络,架设n-1条线路即可。如何以最低的经济代价建设这个通信网,是一个网络的最小生成树问题。
2)实验要求:利用Prim算法求网的最小生成树。
3) 实现提示:通信线路一旦建立,必然是双向的。因此,构造最小生成树的网一定是无向网。为简单起见,图的顶点数不超过10个,网中边的权值设置成小于100。
#include<iostream>
using namespace std;
typedef struct Arc{
int quan;
}AdjMatrix[500][500]; //矩阵
typedef struct Graph{
AdjMatrix arcs;
int vexnum,arcnum;
};
int main(){
int n,m;
Graph G;
cout<<"请输入顶点数和边数"<<endl;
cin>>n>>m;
int i,j;
for(i=1;i<=n;i++){ //初始化矩阵
for(j=1;j<=n;j++){
G.arcs[i][j].quan = 99999;
}
}
int m1 = m;
int a,b,c;
int P;
cout<<"请输入各边信息"<<endl;
while(m1--){ //赋权值
cin>>a>>b>>c;
G.arcs[a][b].quan = c;
G.arcs[b][a].quan = c;
}
int u[1000] = {0};
int v[1000] = {0};
for(i=2;i<=n;i++){
v[i] = i;
}
u[1] = 1;
int n1 = n-1;
int nowi,nowj,sum=0;
while(n1--){
i=1;
int min = 99999;
while(i != n+1){
if(u[i]!=0){
j=1;
while(j != n+1){
if(G.arcs[u[i]][v[j]].quan<=min && v[j]!=0){
min = G.arcs[u[i]][v[j]].quan;
nowi = u[i];
nowj = v[j];
}
j++;
}
}
i++;
}
G.arcs[nowi][nowj].quan = 99999;
G.arcs[nowj][nowi].quan = 99999;
sum += min;
u[nowj] = nowj;
v[nowj] = 0;
}
cout<<"最小代价为:"<<endl;
cout<<sum;
return 0;
}