第1关:迷宫问题
任务描述
密密被困在一个迷宫里,迷宫有n个路口,编号为1-n。密密现在站在第一个路口,出口编号为m。先给出每个路口通向何处,问密密能否逃出迷宫。
编程要求
输入
多组数据,每组数据n+2行。第一行为一个正整数n代表路口的个数,之后n行,这n行中的第i行为第i个路口的向左路口、向前路口、向右路口。最后一行为一个正整数m代表迷宫的终点。当n=0时输入结束。
输出
每组数据输出一行,若密密能走出迷宫,输出“YES”,否则输出“NO”。
测试说明
平台会对你编写的代码进行测试:
测试输入:
6
0 2 0
3 5 6
0 0 4
0 0 0
0 0 0
7 0 0
7
3
2 0 0
0 0 0
0 0 0
3
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 1;
}
for(int i=0;i<3;i++)
{
if(a[k][i]!=0&&a[k][i]!=k)
{
if(DFS(a[k][i],a)==1)
{
tag=1;
return 1;
}
}
}
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关:基于邻接表的深度优先遍历
任务描述
一个连通图采用邻接表作为存储结构。设计一个算法,实现从顶点v出发的深度优先遍历的非递归过程。
编程要求
输入
多组数据,每组m+2数据行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个整数h和k,代表边依附的两个顶点。第m+2行有一个整数d,代表从d开始遍历。当n和m都等于0时,输入结束。
输出
每组数据输出一行,为深度优先搜索的遍历结果。每两个数字之间用空格隔开。
测试说明
平台会对你编写的代码进行测试:
测试输入:
3 2
1 2
1 3
1
2 1
1 2
2
0
0
预期输出:
1 3 2
2 1
上答案:
#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************/
Push(S,v);//入栈
visited[v]=true;//标记v已经被访问
cout<<v<<" ";
while(!StackEmpty(S))//栈不空时循环
{
int w=S.top[-1];//取栈顶元素w
ArcNode *p=G.vertices[w].firstarc;
while(p!=NULL)
{
if(!visited[p->data])//若p->data未被访问
{
Push(S,p->data);//将其入栈
visited[p->data]=true;
cout<<p->data;
if(p->nextarc!=NULL)
{
cout<<" ";
}
break;
}
p=p->nextarc;
}
if(p==NULL)
{
Pop(S,w);//若w的所有邻接点都被访问完了,弹出栈
}
}
// cout<<endl;
/**************end************/
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break;
ALGraph G;
SqStack S;
InitStack(S);
CreateUDG(G,n,m); //创建无向图G
int d; //从d开始遍历
cin>>d;
DFS(G,d,S);
cout<<endl;
//基于邻接表的深度优先遍历
}
return 0;
}
第3关:基于邻接表的长度为k的简单路径的求解
任务描述
一个连通图采用邻接表作为存储结构。设计一个算法,判断无向图中任意给定的两点是否存在一条长度为k的简单路径。
编程要求
输入
多组数据,每组m+3数据行。第一行有两个数字n,m和k,代表有n个顶点,m条边和长度k。第二行有n个字符,代表n个顶点的编号。第三行到第m+2行每行有两个字符h和p,代表边依附的两个顶点。每条边的长度为1。第m+3行有两个字符d和f,代表需要判断的两个字符。
输出
每组数据输出一行。若存在路径输出“YES”,反之输出“NO”。
测试说明
平台会对你编写的代码进行测试:
测试输入:
3 2 2
abc
ab
bc
ac
4 2 5
bcsw
bs
sw
bw
0 0 0
预期输出:
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.arcnum=arcnum;
G.vexnum=vexnum;
for(int i=0;i<G.vexnum;i++)
{
G.vertices[i].data=ch[i];
G.vertices[i].firstarc=NULL; //初始化没有边
}
//输入各边,构造邻接表
for(int k=0;k<G.arcnum;k++)
{
char h,p;
cin>>h>>p;
int i=Locate(ch,h);
int j=Locate(ch,p);
ArcNode *q=(ArcNode*)malloc(sizeof(ArcNode)); //向内存申请空间,生成边结点*q
q->adjvex=j; //邻接点编号为j
q->nextarc=G.vertices[i].firstarc; //将*q的指针指向顶点i的边链表头结点
G.vertices[i].firstarc=q; //将当前的边*q置为顶点i的边链表头结点
q=(ArcNode*)malloc(sizeof(ArcNode)); //向内存申请空间,生成边结点*q
q->adjvex=i; //邻接点编号为i
q->nextarc=G.vertices[j].firstarc; //将*q的指针指向顶点j的边链表头结点
G.vertices[j].firstarc=q; //将当前的边*q置为顶点j的边链表头结点
}
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;
}