第1关:迷宫问题
任务描述
密密被困在一个迷宫里,迷宫有n个路口,编号为1-n。密密现在站在第一个路口,出口编号为m。先给出每个路口通向何处,问密密能否逃出迷宫。
编程要求
输入
多组数据,每组数据n+2行。第一行为一个正整数n代表路口的个数,之后n行,这n行中的第i行为第i个路口的向左路口、向前路口、向右路口。最后一行为一个正整数m代表迷宫的终点。当n=0时输入结束。
输出
每组数据输出一行,若密密能走出迷宫,输出“YES”,否则输出“NO”。
#include <iostream>
using namespace std;
int m,n;//m:出口编号 n:入口
int tag;//输出标记
int DFS(int k,int (*a)[3])
{//深度搜索第k层,k:当前路口
/**************begin************/
if(k==m) //到达出口
{
tag=1;
return 0;
}
for(int i=0;i<3;i++)//遍历向左路口、向前路口、向右路口
{
if(0!=a[k][i]&&tag!=1)//如果当前路口有通路,并且没有走过
{
DFS(a[k][i],a);//进入下一个路口 ,递归
}
}
return 0;
/**************end************/
}
int main()
{
while(cin>>n)
{
if(n==0)break;
int i,j;
tag=0;
int a[n+1][3];//迷宫
for(i=1;i<=n;i++)
for(j=0;j<3;j++)
cin>> a[i][j];
cin>>m;
DFS(1,a);//从第一层开始搜索
if(tag==1)
cout<<"YES"<<endl;
else if(tag==0)
cout<<"NO"<<endl;
}
return 0;
}
第2关:基于Dijsktra算法的最短路径求解
任务描述
一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知。给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间的最短路径。
编程要求
输入
多组数据,每组数据有m+3行。第一行为两个整数n和m,分别代表城市个数n和路径条数m。第二行有n个字符,代表每个城市的名字。第三行到第m+2行每行有两个字符a和b和一个整数d,代表从城市a到城市b有一条距离为d的路。最后一行为两个字符,代表待求最短路径的城市起点和终点。当n和m都等于0时,输入结束。
输出
每组数据输出两行。第一行为一个整数,为从起点到终点之间最短路的长度。第二行为一串字符串,代表该路径。每两个字符之间用空格隔开。
#include<iostream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MaxInt 32767 //最大值
#define MVNum 100 //最大数量
using namespace std;
int D[MVNum]; //D[i]记录从源到终端的当前最短
int Path[MVNum]; //路径[i]记录是从源到终端上vi的当前最小序列号
typedef struct
{
char vexs[MVNum]; //点列表
int arcs[MVNum][MVNum]; //连接到短端口阵列
int vexnum; //数字总数
int arcnum; //图中GL的总数
} AMGraph;
int LocateVex(AMGraph G,char u)
{//存储在“返回”表中的标签,无论是否返回
int i;
for(i=0;i<G.vexnum;i++)
if(u==G.vexs[i])
return i;
return ERROR;
}
char OrigialVex(AMGraph G,int u)
{//以下文件u的元素作为表存储在返回表中?
return G.vexs[u];
}
int CreateDN(AMGraph &G,int spot,int edge)
{//使用连接LPG阵列的方法创建定向屏蔽
G.vexnum=spot;
G.arcnum=edge;
int i,j,k,w;
char v1,v2;
for(i=0;i<G.vexnum;++i)
cin>>G.vexs[i]; //输入
for(i=0;i<G.vexnum;++i)
for(j=0;j<G.vexnum;++j)
G.arcs[i][j]=MaxInt;
for(k=0;k<G.arcnum;++k)
{
cin>>v1>>v2>>w; ///输入附着到第一个面板的标签
i=LocateVex(G, v1);
j=LocateVex(G, v2); //确定v1和2之间的位置
G.arcs[i][j]=w;
}//for
return OK;
}
void ShortestPath_DIJ(AMGraph G, char V)
{//用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径
/**************begin************/
int i,n,v,Min,w;
int S[MVNum]; //S[i]记录从源链0到终点
n=G.vexnum; //N列表中的项目数
int v0=LocateVex(G,V);
for(v=0;v<n;++v)
{
S[v]=false; //首为空
D[v]=G.arcs[v0][v]; //分为不同终端的短期数据库的初始初始化更改为右上角的值
if(D[v]<MaxInt)
Path[v]=v0; //V0之间进行选择,并将v的第一个要求设置为V0
else
Path[v]=-1; //如果v0和v0之间没有差异,则v0的第一个要求设置为1
}//for
S[v0]=true; //将0添加到S
D[v0]=0;
for(i=1;i<n;++i)
{
Min=MaxInt;
for(w=0;w<n;++w)
if(!S[w]&&D[w]<Min)
{
v=w;
Min=D[w];
}
S[v]=true; //添加S
for(w=0;w<n;++w)
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
{
D[w]=D[v]+G.arcs[v][w]; //更新D[w]
Path[w]=v; //先前更改w的要求是v
}//if
}//for
/**************end************/
}
void Find(AMGraph G,int v)
{//在路径编号组中查找程序编号
if(Path[v]==-1)
return ;
else
{
Find(G,Path[v]);
cout<<OrigialVex(G,Path[v])<<" "; //输出点列表中标记有路径[v]的元素
}
}
int main()
{
char a,b;
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break;
AMGraph G;
CreateDN(G,n,m); //创建定向屏蔽
cin>>a; //输入
ShortestPath_DIJ(G,a); //如果G的接触点和它的静止点之间有一段短时间
cin>>b; //触点底座b
int v=LocateVex(G,b);//返回地面表中的下一个标记,以验证测量值的数量
cout<<D[v]<<endl; //将它们之间的短距离输出到B
Find(G,v);
cout<<b<<endl;
}
return 0;
}
第3关:六度空间理论
任务描述
“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。
编程要求
输入
多组数据,每组数据m+1行。第一行有两个数字n和m,代表有n个人和m组朋友关系。n个人的编号为1到n。第二行到第m+1行每行包括两个数字a和b,代表这两个人互相认识。当n和m都等于0时,输入结束。
输出
每组数据输出n行,对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。
#include <iostream>
#include <iomanip>
#define MAXSIZE 100
#define INFINITE 36577
using namespace std;
void CreateUDG(int G[][MAXSIZE], int m, int n)
{//使用连接短速度阵列的方法创建
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
G[i][j]=INFINITE; //原始区域中各个时间段的授权值太长,是否将设备存储在行中的单个点
int a, b;
for (int i=0;i<m;i++) { //存储位置被视为封闭组件。存储位置的测试值为负1,存储位置被看作封闭组件
cin>>a>>b;
G[a-1][b-1]=1;
G[b-1][a-1]=1;
}
}
int FindMinPath(bool S[], int D[], int n)
{//选择其中一个条件的当前最短期限,终点为n
int min=INFINITE;
int index=-1;
for (int i=0;i<n;i++) {
if (!S[i]&&D[i]<min) {
min=D[i];
index=i;
}
}
return index;
}
float SixDegree_DIJ(int G[][MAXSIZE], int n, int start)
{//通过这个“新的开始”,我们可以计算法律系统中六个空时间点的数量,而开始是交换机指定时间点的第一级
/**************begin************/
bool S[MAXSIZE]; //S[]是按以下顺序开始的最短时间
int D[MAXSIZE]; //D[]是以下序列到达起点的最短时间
for (int i=0;i<n;i++) { //n结束基于初始激活区域
S[i]=false;
D[i]=INFINITE;
}
S[start]=true; //将起点添加到S
D[start]=0;
for (int i=0;i<n;i++) {
if (G[start][i]!=0)
D[i]=G[start][i];
}
/*--------初始区域完成或完成后,在相同的环境中启动事件,然后要求系统启动到一定的最小时间长度,然后将其添加到S板-------*/
for (int i=0;i<n-1;i++) {
int v=FindMinPath(S, D, n);
if (v==-1) break;
S[v]=true;
for (int w=0;w<n;w++) {
if (!S[w]&&D[w]>D[v]+G[v][w]) {
D[w]=D[v]+G[v][w]; //更新D[w]
}
}
}
/*--------已请求点开始图[]中剩余短周期的数量,剩余短周期数量现在比其他两个短周期数量少,可以作为相关短周期的百分比列出-------*/
float count=1;
for (int i=0;i<n;i++) {
if (D[i]<=6)
count++;
}
return count/n;
/**************end************/
}
int main()
{
int n,m;
while (true) {
cin>>n>>m;
if (n==0&&m==0) break;
int G[MAXSIZE][MAXSIZE]={ 0 };
CreateUDG(G,m,n);
for (int i=0;i<n;i++) { //首次验证n年的中央时间管理后
cout<<i+1<<": "<<fixed<<setprecision(2)<<SixDegree_DIJ(G,n,i)*100<<"%"<<endl;
}
}
return 0;
}
第4关:基于邻接表的新顶点的增加
任务描述
给定一个无向图,在此无向图中增加一个新顶点。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有一个数字f,代表新插入的顶点编号。当n和m都等于0时,输入结束。
输出
每组数据输出n+1行。为增加顶点后的邻接表。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
int data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
int data; //顶点结点的数据域
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int CreateUDG(ALGragh &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;++i) //构造表头结点表
{
G.vertices[i].data=i+1; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,构造邻接表
{
int h,k;
cin>>h>>k; //输入一条边依附的两个顶点h和k
ArcNode* p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=h-1; //邻接点序号为h-1,即顶点在G.vertices中的序号
p1->data=k;
p1->nextarc=G.vertices[h-1].firstarc; //将新结点*p1插入顶点vh-1的边表头部
G.vertices[h-1].firstarc=p1;
ArcNode* p2=new ArcNode; //生成一个新的边结点*p2
p2->adjvex=k-1; //邻接点序号为k-1,即顶点在G.vertices中的序号
p2->data=h;
p2->nextarc=G.vertices[k-1].firstarc; //将新结点*p2插入顶点vk-1的边表头部
G.vertices[k-1].firstarc=p2;
}
return OK;
}
int InsertVex(ALGragh &G)
{//在以邻接表形式存储的无向图G上插入顶点v
/**************begin************/
if((G.vexnum+1)>MVNum) return ERROR; //判断插入操作是否合法
G.vexnum++; //增加图G的顶点数量
cin>>G.vertices[G.vexnum-1].data; //存入新结点对应的链表的头结点数据域
G.vertices[G.vexnum-1].firstarc=NULL; //指针域赋值为NULL
return OK;
/**************end************/
}
int PrintGraph(ALGragh G)
{//输出图G
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vertices[i].data; //先输出顶点信息
ArcNode* p=G.vertices[i].firstarc; //初始化指针p指向与顶点邻接的第一个边结点
if(p==NULL) //不存在与顶点邻接的第一个边结点
{
cout<<endl;
continue;
}
else //存在时遍历边表
{
cout<<" ";
while(p->nextarc)
{
cout<<p->data<<" ";
p=p->nextarc;
}
cout<<p->data<<endl;
}
}
return OK;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
ALGragh G;
CreateUDG(G,n,m); //采用邻接表表示法,创建无向图G
InsertVex(G); //在图G中增添新顶点
PrintGraph(G); //输出图G
}
return 0;
}
第5关:基于邻接矩阵的新顶点的增加
任务描述
给定一个无向图,在此无向图中增加一个新顶点。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有一个数字f,代表新插入的顶点编号。当n和m都等于0时,输入结束。
输出
每组数据输出n+1行。为增加顶点后的邻接矩阵。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct
{//图的邻接矩阵存储表示
int vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGragh;
int CreateUDN(AMGragh &G,int vexnum,int arcnum)
{//采用邻接矩阵表示法,创建无向网G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
int i,j;
for(i=0;i<=G.vexnum;i++) //依次输入顶点信息
G.vexs[i]=i;
for(i=0;i<=G.vexnum;i++) //初始化邻接矩阵,边的权值均置为0
{
for(j=0;j<=G.vexnum;j++)
G.arcs[i][j]=0;
}
int h,k; //一条边依附的两个顶点h和k
for(i=0;i<G.arcnum;i++) //构造邻接矩阵
{
cin>>h>>k;
G.arcs[h-1][k-1]=1; //边的权值置为1
G.arcs[k-1][h-1]=1; //对称边的权值也置为1
}
return OK;
}
int InsertVex(AMGragh &G)
{//在以邻接矩阵形式存储的无向图G上插入顶点
/**************begin************/
if((G.vexnum+1)>MVNum) return ERROR; //判断插入操作是否合法
G.vexnum++; //增加图G的顶点数量
cin>>G.vexs[G.vexnum]; //将新顶点存入顶点表
for(int k=0;k<G.vexnum;k++) //邻接矩阵相应位置的元素置为0
G.arcs[G.vexnum][k]=G.arcs[k][G.vexnum]=0;
return OK;
/**************end************/
}
int OutputUDN(AMGragh G)
{//输出图G
int i,j;
for(i=0;i<=G.vexnum;i++) //输出第一行顶点表
{
if(i!=G.vexnum)
cout<<G.vexs[i]<<" ";
else
cout<<G.vexs[i]<<endl;
}
for(i=0;i<G.vexnum;i++) //输出其余各行
{
cout<<G.vexs[i+1]<<" "; //先输出顶点
for(j=0;j<G.vexnum;j++)
{
if(j!=G.vexnum-1)
cout<<G.arcs[i][j]<<" ";
else
cout<<G.arcs[i][j]<<endl;
}
}
return OK;
}
int main()
{
int n,m; //n个顶点和m条边
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
AMGragh G;
CreateUDN(G,n,m); //采用邻接矩阵表示法,创建无向网G
InsertVex(G); //在以邻接矩阵形式存储的无向图G上插入顶点
OutputUDN(G); //输出图G
}
return 0;
}
第6关:基于邻接表的顶点的删除
任务描述
给定一个无向图,在此无向图中删除一个顶点。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有一个数字f,代表删除的顶点编号。当n和m都等于0时,输入结束。
输出
每组数据输出n-1行。为删除顶点后的邻接表。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
int data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
int data; //顶点结点的数据域
ArcNode* firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int CreateUDG(ALGragh &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;++i) //构造表头结点表
{
G.vertices[i].data=i+1; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,构造邻接表
{
int h,k;
cin>>h>>k; //输入一条边依附的两个顶点h和k
ArcNode* p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=h-1; //邻接点序号为h-1,即顶点在G.vertices中的序号
p1->data=k;
p1->nextarc=G.vertices[h-1].firstarc; //将新结点*p1插入顶点vh-1的边表头部
G.vertices[h-1].firstarc=p1;
ArcNode* p2=new ArcNode; //生成一个新的边结点*p2
p2->adjvex=k-1; //邻接点序号为k-1,即顶点在G.vertices中的序号
p2->data=h;
p2->nextarc=G.vertices[k-1].firstarc; //将新结点*p2插入顶点vk-1的边表头部
G.vertices[k-1].firstarc=p2;
}
return OK;
}
void DeleteAdjList(VNode &List)
{//删除指定顶点链表上的边结点
ArcNode *p=List.firstarc; //结点p用于指代当前结点的前驱,初始化指顶点链表上的第一个边结点
ArcNode *q=List.firstarc->nextarc; //结点q用于指代当前结点;
while (q){
delete p;
p=q;
q=q->nextarc;
}
}
int DeleteVex(ALGragh &G)
{//删除G中顶点f及其相关的弧
/**************begin************/
int i,f; //f代表删除的顶点编号
cin>>f;
DeleteAdjList(G.vertices[f-1]); //删除指定顶点链表上的边结点
for(i=f;i<G.vexnum;i++) //把f的顶点信息删除,后面顶点向前移动
{
G.vertices[i-1]=G.vertices[i];
}
G.vexnum--; //顶点数减1
for(i=0;i<G.vexnum;i++) //遍历图G,删除顶点f相关的边
{
VNode p=G.vertices[i]; //p用于指向当前结点的前驱
VNode q=G.vertices[i]; //q用于指向当前结点
if(p.firstarc->data==f) //如果当前结点的第一条边关联的结点为f,则直接删除该边
{
ArcNode *t=G.vertices[i].firstarc;
G.vertices[i].firstarc=t->nextarc;
delete t;
G.arcnum--;
continue;
}
q.firstarc=q.firstarc->nextarc; //继续比较后面的边结点
while(q.firstarc)
{
if(q.firstarc->data==f) //存在与f相关的边,则删除该边
{
p.firstarc->nextarc=q.firstarc->nextarc;
delete q.firstarc;
G.arcnum--;
break;
}
p.firstarc=q.firstarc; //没找到与f关联的边,指针后移
q.firstarc=q.firstarc->nextarc;
}
}
return OK;
/**************end************/
}
int PrintGraph(ALGragh G)
{//输出图G
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vertices[i].data; //先输出顶点信息
ArcNode* p=G.vertices[i].firstarc; //初始化指针p指向与顶点邻接的第一个边结点
if(p==NULL) //不存在与顶点邻接的第一个边结点
{
cout<<endl;
continue;
}
else //存在时遍历边表
{
cout<<" ";
while(p->nextarc)
{
cout<<p->data<<" ";
p=p->nextarc;
}
cout<<p->data<<endl;
}
}
return OK;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
ALGragh G;
CreateUDG(G,n,m); //采用邻接表表示法,创建无向图G
DeleteVex(G); //删除G中顶点f及其相关的弧
PrintGraph(G); //输出图G
}
return 0;
}
第7关:基于邻接表的新边的增加
任务描述
给定一个无向图,在此无向图中增加一条边。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有两个数字f和g,代表增加的边所依附的两个顶点。当n和m都等于0时,输入结束。
输出
每组数据输出n行。为增加边后的邻接表。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
int data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
int data; //顶点结点的数据域
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int CreateUDG(ALGragh &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;++i) //构造表头结点表
{
G.vertices[i].data=i+1; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,构造邻接表
{
int h,k;
cin>>h>>k; //输入一条边依附的两个顶点h和k
ArcNode* p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=h-1; //邻接点序号为h-1,即顶点在G.vertices中的序号
p1->data=k;
p1->nextarc=G.vertices[h-1].firstarc; //将新结点*p1插入顶点vh-1的边表头部
G.vertices[h-1].firstarc=p1;
ArcNode* p2=new ArcNode; //生成一个新的边结点*p2
p2->adjvex=k-1; //邻接点序号为k-1,即顶点在G.vertices中的序号
p2->data=h;
p2->nextarc=G.vertices[k-1].firstarc; //将新结点*p2插入顶点vk-1的边表头部
G.vertices[k-1].firstarc=p2;
}
return OK;
}
int InsertArc(ALGragh &G)
{//在以邻接表形式存储的无向图G上插入边
/**************begin************/
int h,k;
cin>>h>>k; //输入一条边依附的两个顶点h和k
ArcNode* p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=h-1; //邻接点序号为h-1,即顶点在G.vertices中的序号
p1->data=k;
p1->nextarc=G.vertices[h-1].firstarc; //将新结点*p1插入顶点vh-1的边表头部
G.vertices[h-1].firstarc=p1;
ArcNode* p2=new ArcNode; //生成一个新的边结点*p2
p2->adjvex=k-1; //邻接点序号为k-1,即顶点在G.vertices中的序号
p2->data=h;
p2->nextarc=G.vertices[k-1].firstarc; //将新结点*p2插入顶点vk-1的边表头部
G.vertices[k-1].firstarc=p2;
return OK;
/**************end************/
}
int PrintGraph(ALGragh G)
{//输出图G
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vertices[i].data; //先输出顶点信息
ArcNode* p=G.vertices[i].firstarc; //初始化指针p指向与顶点邻接的第一个边结点
if(p==NULL) //不存在与顶点邻接的第一个边结点
{
cout<<endl;
continue;
}
else //存在时遍历边表
{
cout<<" ";
while(p->nextarc)
{
cout<<p->data<<" ";
p=p->nextarc;
}
cout<<p->data<<endl;
}
}
return OK;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
ALGragh G;
CreateUDG(G,n,m); //采用邻接表表示法,创建无向图G
InsertArc(G); //在图G中增添新边
PrintGraph(G); //输出图G
}
return 0;
}
第8关:基于邻接矩阵的新边的增加
任务描述
给定一个无向图,在此无向图中增加一条边。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有两个数字f和g,代表增加的边所依附的两个顶点。当n和m都等于0时,输入结束。
输出
每组数据输出n行。为增加边后的邻接矩阵。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct
{//图的邻接矩阵存储表示
int vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGragh;
int CreateUDN(AMGragh &G,int vexnum,int arcnum)
{//采用邻接矩阵表示法,创建无向网G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
int i,j;
for(i=0;i<=G.vexnum;i++) //依次输入顶点信息
G.vexs[i]=i;
for(i=0;i<=G.vexnum;i++) //初始化邻接矩阵,边的权值均置为0
{
for(j=0;j<=G.vexnum;j++)
G.arcs[i][j]=0;
}
int h,k; //一条边依附的两个顶点h和k
for(i=0;i<G.arcnum;i++) //构造邻接矩阵
{
cin>>h>>k;
G.arcs[h-1][k-1]=1; //边的权值置为1
G.arcs[k-1][h-1]=1; //对称边的权值也置为1
}
return OK;
}
int InsertArc(AMGragh &G)
{//在以邻接矩阵形式存储的无向图G上插入边
/**************begin************/
int f,g;
cin>>f>>g;
G.arcs[f-1][g-1]=G.arcs[g-1][f-1]=1; //在邻接矩阵上增加对应的边
G.arcnum++; //边数加1
return OK;
/**************end************/
}
int OutputUDN(AMGragh G)
{//输出图G
int i,j;
for(i=0;i<=G.vexnum;i++) //输出第一行顶点表
{
if(i!=G.vexnum)
cout<<G.vexs[i]<<" ";
else
cout<<G.vexs[i]<<endl;
}
for(i=0;i<G.vexnum;i++) //输出其余各行
{
cout<<G.vexs[i+1]<<" "; //先输出顶点
for(j=0;j<G.vexnum;j++)
{
if(j!=G.vexnum-1)
cout<<G.arcs[i][j]<<" ";
else
cout<<G.arcs[i][j]<<endl;
}
}
return OK;
}
int main()
{
int n,m; //n个顶点和m条边
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
AMGragh G;
CreateUDN(G,n,m); //采用邻接矩阵表示法,创建无向网G
InsertArc(G); //在以邻接矩阵形式存储的无向图G上插入边
OutputUDN(G); //输出图G
}
return 0;
}
第9关:基于邻接表的边的删除
任务描述
给定一个无向图,在此无向图中删除一条边。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有两个数字f和g,代表删除的边所依附的两个顶点。当n和m都等于0时,输入结束。
输出
每组数据输出n行。为删除边后的邻接表。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
int data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
int data; //顶点结点的数据域
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int CreateUDG(ALGragh &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;++i) //构造表头结点表
{
G.vertices[i].data=i+1; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,构造邻接表
{
int h,k;
cin>>h>>k; //输入一条边依附的两个顶点h和k
ArcNode* p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=h-1; //邻接点序号为h-1,即顶点在G.vertices中的序号
p1->data=k;
p1->nextarc=G.vertices[h-1].firstarc; //将新结点*p1插入顶点vh-1的边表头部
G.vertices[h-1].firstarc=p1;
ArcNode* p2=new ArcNode; //生成一个新的边结点*p2
p2->adjvex=k-1; //邻接点序号为k-1,即顶点在G.vertices中的序号
p2->data=h;
p2->nextarc=G.vertices[k-1].firstarc; //将新结点*p2插入顶点vk-1的边表头部
G.vertices[k-1].firstarc=p2;
}
return OK;
}
int DeleteArc(ALGragh &G)
{//在以邻接表形式存储的无向图G上删除边
/**************begin************/
int f,g;
cin>>f>>g; //f和g代表删除的边所依附的两个顶点
ArcNode *q,*p;
p=G.vertices[f-1].firstarc; //指针p初始化指向顶点vf-1的边表头部
q=p; //q用于指向*p的前驱结点
while(p->data!=g) //遍历链表寻找顶点g
{
q=p;
p=p->nextarc;
}
if(q==p) //如果与顶点vf-1相连的第一个边表就是待删除顶点
{
G.vertices[f-1].firstarc=p->nextarc;
delete p;
G.arcnum--; //边的数目减1
}
else
{
q->nextarc=p->nextarc;
delete p;
G.arcnum--;
}
p=G.vertices[g-1].firstarc; //指针p初始化指向顶点vg-1的边表头部
q=p; //q用于指向*p的前驱结点
while(p->data!=f) //遍历链表寻找顶点f
{
q=p;
p=p->nextarc;
}
if(q==p) //如果与顶点vg-1相连的第一个边表就是待删除边
{
G.vertices[g-1].firstarc=p->nextarc;
delete p;
G.arcnum--; //边的数目减1
}
else
{
q->nextarc=p->nextarc;
delete p;
G.arcnum--;
}
return OK;
/**************end************/
}
int PrintGraph(ALGragh G)
{//输出图G
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vertices[i].data; //先输出顶点信息
ArcNode* p=G.vertices[i].firstarc; //初始化指针p指向与顶点邻接的第一个边结点
if(p==NULL) //不存在与顶点邻接的第一个边结点
{
cout<<endl;
continue;
}
else //存在时遍历边表
{
cout<<" ";
while(p->nextarc)
{
cout<<p->data<<" ";
p=p->nextarc;
}
cout<<p->data<<endl;
}
}
return OK;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
ALGragh G;
CreateUDG(G,n,m); //采用邻接表表示法,创建无向图G
DeleteArc(G); //在图G中增添新顶点
PrintGraph(G); //输出图G
}
return 0;
}
第10关:基于邻接矩阵的边的删除
任务描述
给定一个无向图,在此无向图中删除一条边。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有两个数字f和g,代表删除的边所依附的两个顶点。当n和m都等于0时,输入结束。
输出
每组数据输出n行。为删除边后的邻接矩阵。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct
{//图的邻接矩阵存储表示
int vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGragh;
int CreateUDN(AMGragh &G,int vexnum,int arcnum)
{//采用邻接矩阵表示法,创建无向网G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
int i,j;
for(i=0;i<=G.vexnum;i++) //依次输入顶点信息
G.vexs[i]=i;
for(i=0;i<=G.vexnum;i++) //初始化邻接矩阵,边的权值均置为0
{
for(j=0;j<=G.vexnum;j++)
G.arcs[i][j]=0;
}
int h,k; //一条边依附的两个顶点h和k
for(i=0;i<G.arcnum;i++) //构造邻接矩阵
{
cin>>h>>k;
G.arcs[h-1][k-1]=1; //边的权值置为1
G.arcs[k-1][h-1]=1; //对称边的权值也置为1
}
return OK;
}
int DeleteArc(AMGragh &G)
{//在以邻接矩阵形式存储的无向图G上删除边
/**************begin************/
int f,g; //f和g代表删除的边所依附的两个顶点
cin>>f>>g;
G.arcs[f-1][g-1]=G.arcs[g-1][f-1]=0; //在邻接矩阵上删除边
G.arcnum--; //边数减1
return OK;
/**************end************/
}
int OutputUDN(AMGragh G)
{//输出图G
int i,j;
for(i=0;i<=G.vexnum;i++) //输出第一行顶点表
{
if(i!=G.vexnum)
cout<<G.vexs[i]<<" ";
else
cout<<G.vexs[i]<<endl;
}
for(i=0;i<G.vexnum;i++) //输出其余各行
{
cout<<G.vexs[i+1]<<" "; //先输出顶点
for(j=0;j<G.vexnum;j++)
{
if(j!=G.vexnum-1)
cout<<G.arcs[i][j]<<" ";
else
cout<<G.arcs[i][j]<<endl;
}
}
return OK;
}
int main()
{
int n,m; //n个顶点和m条边
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
AMGragh G;
CreateUDN(G,n,m); //采用邻接矩阵表示法,创建无向网G
DeleteArc(G); //在以邻接矩阵形式存储的无向图G上删除边
OutputUDN(G); //输出图G
}
return 0;
}
第11关:基于邻接表的深度优先遍历
任务描述
一个连通图采用邻接表作为存储结构。设计一个算法,实现从顶点v出发的深度优先遍历的非递归过程。
编程要求
输入
多组数据,每组m+2数据行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个整数h和k,代表边依附的两个顶点。第m+2行有一个整数d,代表从d开始遍历。当n和m都等于0时,输入结束。
输出
每组数据输出一行,为深度优先搜索的遍历结果。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSIZE 100
using namespace std;
typedef struct ArcNode
{//边结点
int data;
struct ArcNode *nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
int data;
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MAXSIZE]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGraph;
typedef struct
{//顺序栈
int *base; //栈底指针
int *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
void InitStack(SqStack &S)
{//顺序栈的初始化
S.base=new int[MAXSIZE]; //动态分配一个最大容量MAXSIZE的数组空间
S.top=S.base; //top初始为base,空栈
S.stacksize=MAXSIZE;
}
void Push(SqStack &S,int e)
{//入栈操作
if(S.top-S.base==S.stacksize) //栈满
return;
*S.top=e; //元素e压入栈顶
S.top++; //栈顶指针加1
}
void Pop(SqStack &S,int &e)
{//出栈操作
if(S.base==S.top) //栈空
return;
S.top--; //栈顶指针减1
e=*S.top; //将栈顶元素赋给e
}
bool StackEmpty(SqStack S)
{//判空操作
if(S.base==S.top) //栈空返回true
return true;
return false;
}
bool visited[MAXSIZE]; //访问标志数组,初始为false
int CreateUDG(ALGraph &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MAXSIZE) return ERROR; //超出最大顶点数则结束函数
int i,h,k;
for(i=1;i<=G.vexnum;i++) //构造表头结点表
{
G.vertices[i].data=i;
visited[i]=false;
G.vertices[i].firstarc=NULL;
}
ArcNode *p1,*p2;
for(i=0;i<G.arcnum;i++) //输入各边,头插法构造邻接表
{
cin>>h>>k;
p1=new ArcNode;
p1->data=k;
p1->nextarc=G.vertices[h].firstarc;
G.vertices[h].firstarc=p1;
p2=new ArcNode;
p2->data=h;
p2->nextarc=G.vertices[k].firstarc;
G.vertices[k].firstarc=p2;
}
return OK;
}
void DFS(ALGraph G,int v,SqStack S)
{//从第v个顶点出发非递归实现深度优先遍历图G
/**************begin************/
InitStack(S); //构造一个空栈
Push(S,v); //顶点v进栈
int cnt=0,k;
ArcNode *p;
while(!StackEmpty(S))
{
Pop(S,k); //栈顶元素k出栈
if(!visited[k]) //k未被访问
{
cnt++;
if(cnt<G.vexnum) //访问第k个顶点
cout<<k<<" ";
else
cout<<k<<endl;
visited[k]=true;
}
p=G.vertices[k].firstarc; //p指向k的边链表的第一个边结点
while(p!=NULL) //边结点非空
{
if(!visited[p->data]) //如果p->data未被访问,p->data进栈
Push(S,p->data);
p=p->nextarc; //p指向下一个边结点
}
}//while
/**************end************/
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break;
ALGraph G;
SqStack S;
CreateUDG(G,n,m); //创建无向图G
int d; //从d开始遍历
cin>>d;
DFS(G,d,S); //基于邻接表的深度优先遍历
}
return 0;
}
第12关:最长的最短路径的求解
任务描述
设计一个算法,求图G中距离顶点v的最短路径长度最大的一个顶点。
编程要求
输入
多组数据,每组数据m+2行。每组数据第一行为两个整数n和m,代表有n个顶点m条路。顶点编号为1到n。第二行到第m+1行每行有三个整数a,b和c,代表顶点a和顶点b之间有一条长度为c的路。第m+2有一个整数v,代表顶点v。当n和m都等于0时,输入结束。
输出
每组数据输出两行。第一行为最短路径最长的顶点编号c,第二行为两点的最短距离d。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
#define MaxInt 32767
using namespace std;
typedef struct
{//图的邻接矩阵存储表示
int vexnum,arcnum; //图的当前顶点数和边数
int vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
}AMGraph;
int CreateUDN(AMGraph &G,int vexnum,int arcnum)
{//采用邻接矩阵表示法,创建无向网G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
int i,j,a,b,c;
for(i=1;i<=G.vexnum;i++)
G.vexs[i]=i;
for(i=1;i<=G.vexnum;i++) //初始化邻接矩阵,边的权值均置为极大值
for(j=1;j<=G.vexnum;j++)
G.arcs[i][j]=MaxInt;
for(i=0;i<G.arcnum;i++) //顶点a和顶点b之间有一条长度为c的路
{
cin>>a>>b>>c;
G.arcs[a][b]=c;
G.arcs[b][a]=c;
}
return OK;
}
void ShortPathMAX(AMGraph G,int v0)
{//用Dijkstra算法求图G中距离顶点v0的最短路径长度最大的一个顶点
/**************begin************/
bool* S=new bool[G.vexnum+1]; //顶点集S,初始值为false
int* Path=new int[G.vexnum+1];
int* D=new int[G.vexnum+1]; //保存v0到其他所有顶点的最短路径
int i,j,Min,Min_j,k,Max,Max_j;
for(i=1;i<=G.vexnum;i++) //顶点依次初始化
{
S[i]=false; //S初始为空集
D[i]=G.arcs[v0][i]; //将v0到各个终点的最短路径长度初始化为弧上的权值
if(D[i]==MaxInt)
Path[i]=ERROR; //如果v0和v之间无弧,则将v的前驱置为ERROR
else
Path[i]=v0; //如果v0和v之间有弧,则将v的前驱置为v0
}
S[v0]=true; //将v0加入S
D[v0]=0; //源点到源点的距离为0
/*------初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集------*/
for(i=1;i<=G.vexnum;i++) //对其余顶点,依次进行计算
{
Min=MaxInt;
for(j=1;j<=G.vexnum;j++)
{
if(!S[j]&&D[j]<Min) //选择一条当前的最短路径,终点为Min_j
{
Min_j=j;
Min=D[j];
}
}
S[Min_j]=true; //将Min_j加入S
for(k=1;k<=G.vexnum;k++) //更新从v0出发到集合V-S上所有顶点的最短路径长度
{
if(!S[k]&&(D[Min_j]+G.arcs[Min_j][k]<D[k]))
{
D[k]=D[Min_j]+G.arcs[Min_j][k]; //更新D[k]
Path[k]=Min_j; //更新k的前驱为Min_j
}//if
}//for
/*------------最短路径求解完毕,设距离顶点v0的最短路径长度最大的一个顶点为Max_j-----------*/
Max=0;
for(i=1;i<=G.vexnum;i++)
{
if(Max<D[i])
{
Max=D[i];
Max_j=i;
}//if
}//for
cout<<Max_j<<endl; //最短路径最长的顶点编号
cout<<Max<<endl; //两点的最短距离
}//for
/**************end************/
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break;
AMGraph G;
CreateUDN(G,n,m); //创建无向网G
int v;
cin>>v;
ShortPathMAX(G,v); //最长的最短路径的求解
}
return 0;
}
第13关:基于深度优先搜索的两顶点路径存在与否的判断
任务描述
设计一个算法,试基于深度优先搜索判断以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i≠j)。
编程要求
输入
多组数据,每组m+3数据行。第一行有两个数字n和m,代表有n个顶点和m条边。第二行有n个字符,代表n个顶点的编号。第三行到第m+2行每行有两个字符h和k,代表边依附的两个顶点。第m+3行有两个字符vi和vj,代表需要判断的两个顶点。当n和m都等于0时,输入结束。
输出
每组数据输出一行。若存在路径输出“YES”,反之输出“NO”。
#include<iostream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MaxInt 32767 //表示极大值,即∞
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
char data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
char data; //顶点结点的数据域
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int Locate(char ch[],char h)
{//存在则返回h在数组中的下标,否则返回ERROR
int i;
for(i=0;ch[i]!='\0';i++)
{
if(ch[i]==h)
return i;
}
return ERROR;
}
bool visited[MVNum]; //访问标记数组,已访问顶点的值记为true,初始值为false
int CreateUDG(ALGragh &G,int vexnum,int arcnum,char ch[])
{//采用邻接表表示法,创建无向图G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;i++) //构造表头结点表
{
G.vertices[i].data=ch[i]; //输入顶点值
visited[i]=false;
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,头插法构造邻接表
{
char h,p;
cin>>h>>p; //输入一条边依附的两个顶点h和p
ArcNode* p1=new ArcNode;
int pos2=Locate(ch,p);
p1->adjvex=pos2;
p1->data=p;
int pos1=Locate(ch,h);
p1->nextarc=G.vertices[pos1].firstarc;
G.vertices[pos1].firstarc=p1;
ArcNode* p2=new ArcNode;
p2->adjvex=pos1;
p2->data=h;
p2->nextarc=G.vertices[pos2].firstarc;
G.vertices[pos2].firstarc=p2;
}
return OK;
}
int level=1; //递归的层数
int PathDFS(ALGragh G,int i,int j)
{//基于深度优先搜索判断有向图G中顶点i到j是否有路径,是则返回1,否则返回0
/**************begin************/
if(i==j) return OK; //递归结束的条件,首尾相遇,存在路径
else
{
visited[i]=true; //顶点i访问标志为true
ArcNode *p;
for(p=G.vertices[i].firstarc;p;p=p->nextarc,level--)
{
level++; //递归层加1
int k=p->adjvex;
if(!visited[k]&&PathDFS(G,k,j))
return OK; //i下游的顶点到j有路径
}//for
}//else
if(level==1) return 0; //i到j没有路径
return 0; //函数默认返回0
/**************end************/
}
int main()
{
int n,m; //n个顶点,m条边和长度k
while(cin>>n>>m)
{
if(n==0&&m==0) break;
char ch[MVNum];
cin>>ch;
ALGragh G;
CreateUDG(G,n,m,ch); //创建无向图G
char vi,vj; //d和f代表需要判断的两个字符
cin>>vi>>vj;
int pi=Locate(ch,vi);
int pj=Locate(ch,vj);
if(PathDFS(G,pi,pj))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
第14关:基于邻接表的长度为k的简单路径的求解
任务描述
一个连通图采用邻接表作为存储结构。设计一个算法,判断无向图中任意给定的两点是否存在一条长度为k的简单路径。
编程要求
输入
多组数据,每组m+3数据行。第一行有两个数字n,m和k,代表有n个顶点,m条边和长度k。第二行有n个字符,代表n个顶点的编号。第三行到第m+2行每行有两个字符h和p,代表边依附的两个顶点。每条边的长度为1。第m+3行有两个字符d和f,代表需要判断的两个字符。
输出
每组数据输出一行。若存在路径输出“YES”,反之输出“NO”。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
int adjvex; //邻接点域:该边所指向的顶点的位置
char data; //数据域:存储和边相关的信息
struct ArcNode* nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
char data; //顶点结点的数据域
ArcNode *firstarc; //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //AdjList表示邻接表类型
typedef struct
{//邻接表
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和边数
}ALGragh;
int Locate(char ch[],char h)
{//存在则返回h在数组中的下标,否则返回ERROR
int i;
for(i=0;ch[i]!='\0';i++)
{
if(ch[i]==h)
return i;
}
return ERROR;
}
bool visited[MVNum]; //访问标记数组,已访问顶点的值记为true
bool PathLenK(ALGragh G,int pD,int pF,int k)
{//判断邻接表方式存储的有向图G的顶点pD到pF是否存在长度为k的简单路径
if(pD==pF&&k==0) return true; //找到了一条路径,且长度符合要求
else if(k>0) //从结点pD开始遍历,p为pD的边链表的第一个结点
{
visited[pD]=true;
ArcNode *p;
for(p=G.vertices[pD].firstarc;p;p=p->nextarc)
{
int v=p->adjvex;
if(!visited[v]) //v从未被访问过
{
if(PathLenK(G,v,pF,k-1))
return true; //递归继续遍历判断pD到pF,且剩余路径长度减1
}
}
visited[pD]=false;//允许曾经被访问过的结点出现在另一条路径中
}
return false; //没找到
}
int CreateUDG(ALGragh &G,int vexnum,int arcnum,char ch[])
{//采用邻接表表示法,创建无向图G
/**************begin************/
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
for(int i=0;i<G.vexnum;i++) //构造表头结点表
{
G.vertices[i].data=ch[i]; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
for(int j=0;j<G.arcnum;j++) //输入各边,头插法构造邻接表
{
char h,p;
cin>>h>>p; //输入一条边依附的两个顶点h和p
ArcNode* p1=new ArcNode;
int pos2=Locate(ch,p);
p1->adjvex=pos2;
p1->data=p;
int pos1=Locate(ch,h);
p1->nextarc=G.vertices[pos1].firstarc;
G.vertices[pos1].firstarc=p1;
ArcNode* p2=new ArcNode;
p2->adjvex=pos1;
p2->data=h;
p2->nextarc=G.vertices[pos2].firstarc;
G.vertices[pos2].firstarc=p2;
}
return OK;
/**************end************/
}
int main()
{
int n,m,k; //n个顶点,m条边和长度k
while(cin>>n>>m>>k)
{
if(n==0&&m==0&&k==0) break;
char ch[MVNum];
cin>>ch;
ALGragh G;
CreateUDG(G,n,m,ch); //创建无向图G
char d,f; //d和f代表需要判断的两个字符
cin>>d>>f;
int pd=Locate(ch,d);
int pf=Locate(ch,f);
if(PathLenK(G,pd,pf,k))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
第15关:基于邻接矩阵的顶点的删除
任务描述
给定一个无向图,在此无向图中删除一个顶点。
编程要求
输入
多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有一个数字f,代表删除的顶点编号。当n和m都等于0时,输入结束。
输出
每组数据输出n-1行。为删除顶点后的邻接矩阵。每两个数字之间用空格隔开。
#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100 //最大顶点数
using namespace std;
typedef struct
{//图的邻接矩阵存储表示
int vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGragh;
int CreateUDN(AMGragh &G,int vexnum,int arcnum)
{//采用邻接矩阵表示法,创建无向网G
G.vexnum=vexnum; //输入总顶点数
G.arcnum=arcnum; //输入总边数
if(G.vexnum>MVNum) return ERROR; //超出最大顶点数则结束函数
int i,j;
for(i=0;i<=G.vexnum;i++) //依次输入顶点信息
G.vexs[i]=i;
for(i=0;i<=G.vexnum;i++) //初始化邻接矩阵,边的权值均置为0
{
for(j=0;j<=G.vexnum;j++)
G.arcs[i][j]=0;
}
int h,k; //一条边依附的两个顶点h和k
for(i=0;i<G.arcnum;i++) //构造邻接矩阵
{
cin>>h>>k;
G.arcs[h-1][k-1]=1; //边的权值置为1
G.arcs[k-1][h-1]=1; //对称边的权值也置为1
}
return OK;
}
int DeleteVex(AMGragh &G)
{//在以邻接矩阵形式存储的无向图G上删除顶点v
/**************begin************/
int i,j,f; //f代表删除的顶点编号
cin>>f;
for(i=f-1;i<G.vexnum-1;i++) //从目标顶点所在行开始,用下一行的边的权值逐行覆盖上一行边的权值
{
for(j=0;j<G.vexnum;j++)
{
G.arcs[i][j]=G.arcs[i+1][j];
}
}
G.vexnum--; //图的顶点数减1
for(i=0;i<G.vexnum;i++) //从目标顶点所在列开始,用后一列的边的权值逐列覆盖前一列边的权值
for(j=f-1;j<G.vexnum;j++)
{
G.arcs[i][j]=G.arcs[i][j+1];
}
for(i=f;i<=G.vexnum;i++) //更新顶点表
G.vexs[i]=G.vexs[i+1];
return OK;
/**************end************/
}
int OutputUDN(AMGragh G)
{//输出图G
int i,j;
for(i=0;i<=G.vexnum;i++) //输出第一行顶点表
{
if(i!=G.vexnum)
cout<<G.vexs[i]<<" ";
else
cout<<G.vexs[i]<<endl;
}
for(i=0;i<G.vexnum;i++) //输出其余各行
{
cout<<G.vexs[i+1]<<" "; //先输出顶点
for(j=0;j<G.vexnum;j++)
{
if(j!=G.vexnum-1)
cout<<G.arcs[i][j]<<" ";
else
cout<<G.arcs[i][j]<<endl;
}
}
return OK;
}
int main()
{
int n,m; //n个顶点和m条边
while(cin>>n>>m)
{
if(n==0&&m==0) break; //输入结束标志
AMGragh G;
CreateUDN(G,n,m); //采用邻接矩阵表示法,创建无向网G
DeleteVex(G); //在以邻接矩阵形式存储的无向图G上删除顶点v
OutputUDN(G); //输出图G
}
return 0;
}