题目一: 图的遍历
[问题描述]
对给定图,实现图的深度优先遍历和广度优先遍历。
[基本要求]
以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。
【测试数据】
由学生依据软件工程的测试技术自己确定。
输入样例:
4 4
0 1 2 3
0 1
0 2
0 3
2 3
输出样例:
输出邻接表:
0:3 2 1
1:0
2:3 0
3:2 0
Depth first search:
输入开始节点:2
2301
Breadth first search:
输入开始节点:3
3201
CODE:
#include <iostream>
#include <cstring>
using namespace std;
const int MX=100;
int visit[MX]; //标记是否被遍历过
typedef struct arcnode
{
int adjvex; //每链表中所保存的信息,代表与头节点所连的节点的编号
struct arcnode *next; //指向下一个结点
} arcnode;
typedef struct vnode
{
int data; //每个链表中的头节点信息;图中每个节点的信息
arcnode *firstarc;
} vnode,adjlist[MX];
typedef struct
{
adjlist vertices; //头节点数组
int vexnum,arcnum; //节点个数、边的个数
} algraph;
void creatudg(algraph &g) //创建图
{
cin>>g.vexnum>>g.arcnum; //输入节点个数、边的个数
int i,j;
int v1,v2,n,m;
for(i=0; i<g.vexnum; i++) //输入图中的节点信息
{
cin>>n;
g.vertices[i].data=n;
g.vertices[i].firstarc=NULL;
}
for(i=0; i<g.arcnum; i++)
{
cin>>v1>>v2; //输入一条边
n=m=-1;
for(j=0; j<g.vexnum; j++) //在图中寻找这两个结点,因为是无向图所以要两个都要找
{
if(g.vertices[j].data==v1)
n=j;
if(g.vertices[j].data==v2)
m=j;
if(n!=-1&&m!=-1)
break;
}
//采用头插法将两个编号保存在链表内
arcnode *p1=new arcnode;
p1->adjvex=m;
p1->next=g.vertices[n].firstarc;
g.vertices[n].firstarc=p1;
arcnode *p2=new arcnode;
p2->adjvex=n;
p2->next=g.vertices[m].firstarc;
g.vertices[m].firstarc=p2;
}
}
void out(algraph g) //输出邻接表
{
int i;
for(i=0; i<g.vexnum; i++)
{
cout<<g.vertices[i].data<<":";
while(g.vertices[i].firstarc!=NULL)
{
cout<<g.vertices[i].firstarc->adjvex<<" "; //只是输出了该节点所连的编号
g.vertices[i].firstarc=g.vertices[i].firstarc->next;
}
cout<<endl;
}
}
void dfs(algraph g,int v)
{
cout<<v; //v为结点数据
int i;
for(i=0;i<g.vexnum;i++) //在数组里找到该节点,并标记该节点
{
if(g.vertices[i].data==v)
{
visit[i]=1;
break;
}
}
while(g.vertices[i].firstarc!=NULL) //将该链表遍历完
{
if(visit[g.vertices[i].firstarc->adjvex]) //如果已被标记则指向下一个
{
g.vertices[i].firstarc=g.vertices[i].firstarc->next;
}
else
{
dfs(g,g.vertices[g.vertices[i].firstarc->adjvex].data); //若未被标记则遍历代表该节点的链表
}
}
}
//队列
typedef struct QNode
{
int base;
struct QNode *next;
} QNode,*QueuePtr;
typedef struct
{
QueuePtr f,r;
} LinkQueue;
void InitQueue(LinkQueue &q)
{
q.f=q.r=new QNode;
q.f->next=NULL;
return;
}
void Qpush(LinkQueue &q,int t)
{
QueuePtr p;
p=new QNode;
p->base=t;
p->next=NULL;
q.r->next=p;
q.r=p;
return;
}
bool Empty(LinkQueue q)
{
return q.f==q.r;
}
void Qpop(LinkQueue &q)
{
if(!Empty(q))
q.f=q.f->next;
}
void bfs(LinkQueue &q,algraph g,int v)
{
Qpush(q,v);
while(!Empty(q)) //结束条件为队列为空
{
int n=q.f->next->base;
cout<<n;
int i;
for(i=0;i<g.vexnum;i++) //在数组中寻找该该节点的编号,并标记
{
if(g.vertices[i].data==n)
{
visit[i]=0;
break;
}
}
while(g.vertices[i].firstarc!=NULL) //将该链表中未被标记的全部进队列,进队列后标记
{
if(visit[g.vertices[i].firstarc->adjvex])
{
visit[g.vertices[i].firstarc->adjvex]=0;
Qpush(q,g.vertices[g.vertices[i].firstarc->adjvex].data);
}
g.vertices[i].firstarc=g.vertices[i].firstarc->next;
}
Qpop(q);
}
}
int main()
{
memset(visit,0,sizeof(visit)); //记录被标记过的结点
algraph g;
creatudg(g); //创建图
cout<<"输出邻接表:"<<endl;
out(g);
int v;
cout<<"Depth first search:"<<endl;
memset(visit,0,sizeof(visit));
cout<<"输入开始节点:";
cin>>v;
dfs(g,v);
cout<<endl;
cout<<"Breadth first search:"<<endl;
cout<<"输入开始节点:";
cin>>v;
LinkQueue q;
InitQueue(q);
bfs(q,g,v);
return 0;
}
/*
4 4
1 2 3 4
4 1
4 2
4 3
2 3
4 5
7 5 6 9
7 9
7 6
7 5
5 6
5 9
*/
题目二:最小生成树问题
[问题描述]
若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
[基本要求]
1.利用克鲁斯卡尔算法求网的最小生成树。
2.要求输出各条边及它们的权值。
[实现提示]
通信线路一旦建成,必然是双向的。因此,构造最小生成树的网一定是无向网。设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数。
图的存储结构的选取应和所作操作相适应。为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组表示图。
[测试数据]
由学生依据软件工程的测试技术自己确定。
输入样例:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
输出样例:
最小生成树为:
0 3 5
2 4 5
3 5 6
5 1 7
1 4 7
4 6 9
CODE:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int parent[30];
struct Edge
{
int id;
int s;
int e;
int w;
} edge[30];
bool cmp(Edge a,Edge b)
{
if(a.w==b.w)
return a.id<b.id;
return a.w<b.w;
}
int find(int x)
{
if(parent[x]!=x)
return parent[x]=find(parent[x]);
return x;
}
int main()
{
int n,m,k,g;
cin>>m;
cin>>n;
for(int i=0; i<n; i++)
{
cin>>edge[i].s>>edge[i].e>>edge[i].w;
edge[i].id=i;
}
sort(edge,edge+n,cmp);
for(int i=0; i<n; i++)
parent[i]=i;
cout<<"最小生成树为:"<<endl;
for(int i=0; i<n; i++)
{
k=find(edge[i].s);
g=find(edge[i].e);
if(k!=g)
{
parent[find(k)]=find(g);
cout<<k<<" "<<g<<" "<<edge[i].w<<endl;
}
}
cout<<endl<<endl;
return 0;
}
题目三:拓扑排序的应用
试编程,为某校计算机科学与技术专业的四年全部课程做一个排课方案。
[测试数据]
自行设计
样例输入:
7 7
a b c d e f g
a g
g f
f e
b c
b d
c d
c e
样例输出:
输出邻接表:
a 0:g
b 0:d c
c 1:e d
d 2:
e 2:
f 1:e
g 1:f
bcdagfe
CODE:
#include <iostream>
#include <cstring>
using namespace std;
const int MX=100;
int visit[MX];
int indegree[MX];
typedef struct arcnode
{
char adjvex;
struct arcnode *next;
} arcnode;
typedef struct vnode
{
char data;
arcnode *firstarc;
} vnode,adjlist[MX];
typedef struct
{
adjlist vertices;
int vexnum,arcnum;
} algraph;
void creatudg(algraph &g)
{
cin>>g.vexnum>>g.arcnum;
int i,j;
int n,m;
char ch,v1,v2;
for(i=0; i<g.vexnum; i++)
{
cin>>ch;
g.vertices[i].data=ch;
g.vertices[i].firstarc=NULL;
}
for(i=0; i<g.arcnum; i++)
{
cin>>v1>>v2;
n=m=-1;
for(j=0; j<g.vexnum; j++)
{
if(g.vertices[j].data==v1)
n=j;
if(g.vertices[j].data==v2)
m=j;
if(n!=-1&&m!=-1)
break;
}
arcnode *p1=new arcnode;
p1->adjvex=g.vertices[m].data;
p1->next=g.vertices[n].firstarc;
g.vertices[n].firstarc=p1;
indegree[m]++;
}
}
void out(algraph g)
{
int i;
for(i=0; i<g.arcnum; i++)
{
cout<<g.vertices[i].data<<" "<<indegree[i]<<":";
while(g.vertices[i].firstarc!=NULL)
{
cout<<g.vertices[i].firstarc->adjvex<<" ";
g.vertices[i].firstarc=g.vertices[i].firstarc->next;
}
cout<<endl;
}
}
typedef struct
{
char *base;
char *top;
int l;
} SqStack;
void InitStack(SqStack &s)
{
s.base=new char[MX];
s.top=s.base;
s.l=MX;
return;
}
void Push(SqStack &s,char ch)
{
if(s.top-s.base==s.l)
return;
*s.top++=ch;
return;
}
bool Empty(SqStack &s)
{
return s.base==s.top;
}
int find(algraph &g,char ch)
{
int i;
for(i=0; i<g.vexnum; i++)
{
if(g.vertices[i].data==ch)
break;
}
return i;
}
void topol(algraph &g)
{
SqStack s;
InitStack(s);
int i;
for(i=0; i<g.vexnum; i++)
{
if(indegree[i]==0)
{
Push(s,g.vertices[i].data);
visit[i]=1;
}
}
while(!Empty(s))
{
cout<<*(s.top-1);
int n=find(g,*(s.top-1));
s.top--;
visit[n]=1;
while(g.vertices[n].firstarc!=NULL)
{
indegree[find(g,g.vertices[n].firstarc->adjvex)]--;
g.vertices[n].firstarc=g.vertices[n].firstarc->next;
}
for(i=0; i<g.vexnum; i++)
{
if(visit[i]==0&&indegree[i]==0)
{
Push(s,g.vertices[i].data);
visit[i]=1;
}
}
}
}
int main()
{
int visit[MX];
memset(visit,0,sizeof(visit));
memset(indegree,0,sizeof(indegree));
algraph g;
creatudg(g);
cout<<"Êä³öÁÚ½Ó±í:"<<endl;
out(g);
topol(g);
cout<<endl;
return 0;
}
题目四:最短路径问题
[问题描述]
给定一个无向网,可以求得任意一对顶点之间的最短路径。
[基本要求]
以邻接矩阵为存储结构,实现弗洛伊德算法求解每一对顶点之间的最短路径及最短路径长度。
[测试数据]
由学生依据软件工程的测试技术自己确定。
样例输入:
4 8
1 3 2
1 2 9
2 1 5
2 3 8
2 0 3
3 2 6
0 1 1
0 3 4
样例输出:
输入两端点:3 0
最短路径长度:9
路径是:320
1 3
最短路径长度:2
路径是:13
-1 -1
CODE:
#include <iostream>
#include <cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int MX=100;
int d[MX][MX];
int path[MX][MX];
typedef struct
{
int arcs[MX][MX];
int vexnum,arcnum;
} amgraph;
void createudn(amgraph &g)
{
cin>>g.vexnum>>g.arcnum;
int i,j,k,v1,v2,w;
for(i=0; i<g.vexnum; i++)
{
for(j=0; j<g.vexnum; j++)
{
if(i==j)
g.arcs[i][j]=0;
else
g.arcs[i][j]=INF;
}
}
for(k=0; k<g.arcnum; k++)
{
cin>>v1>>v2>>w;
g.arcs[v1][v2]=w;
}
}
void shortestpath(amgraph &g)
{
int i,j,k;
for(i=0; i<g.vexnum; i++)
for(j=0; j<g.vexnum; j++)
{
d[i][j]=g.arcs[i][j];
if(d[i][j]<INF&&i!=j)
path[i][j]=i;
else
path[i][j]=-1;
}
for(k=0; k<g.vexnum; k++)
for(i=0; i<g.vexnum; i++)
for(j=0; j<g.vexnum; 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];
}
}
}
typedef struct
{
int *base;
int *top;
int l;
} SqStack;
void InitStack(SqStack &s)
{
s.base=new int[MX];
s.top=s.base;
s.l=MX;
return;
}
void Push(SqStack &s,int ch)
{
if(s.top-s.base==s.l)
return;
*s.top++=ch;
return;
}
void Pop(SqStack &s)
{
s.top--;
}
bool Empth(SqStack &s)
{
return s.base==s.top;
}
void Path(int n,int m)
{
cout<<"路径是:";
SqStack s;
InitStack(s);
Push(s,m);
while(n!=m)
{
m=path[n][m];
Push(s,m);
}
while(!Empth(s))
{
cout<<*(s.top-1);
Pop(s);
}
}
int main()
{
amgraph g;
createudn(g);
shortestpath(g);
cout<<"输入两端点:";
int n,m;
while(cin>>n>>m)
{
if(n==-1&&m==-1)
break;
cout<<"最短路径长度:"<<d[n][m]<<endl;
Path(n,m);
cout<<endl;
}
return 0;
}