1、题目
某个太空神秘国度中有很多美丽的小村,从太空中可以望见,小村间有路相连,更精确点说,任意两村之间有且仅有一条路径。小村A中有位年轻人爱上了自己村里的美丽姑娘,每天早晨,姑娘都要去小村B里的面包房工作,傍晚6点回家。年轻人终于决定要向姑娘表白,他打算在小村C等着姑娘路过的时候把爱慕说出来,问题是,他不能确定小村C是否在小村B到小村A之间的路径上,你可帮助他解决这个问题吗?
要求建立一个有 N(1≤N≤500000)个结点的连通图,因为说明了“任意两村之间有且仅有一条路径”,所以这是 N 个结点且恰好有 N-1 条边的连通图,每 个 小 村 从 0 到 N-1 编 号 。 建 立 好 村 落 图 后 要 求 输 入 测 试 组 个 数 M(1<=M<=500000),再输入 M 行已建立的村落图中的 A、B、C 村的编号,即测试 M 次 C 是否在 A 和 B 之间的路径上,如果 C 在 A 和 B 之间的路径上,输出YES,否则输出 NO。
2、基本思路
- 在建立图的函数里采用邻接表表示法建立无向村落图,小村个数为 N(1<=N<=500000),且路径数为 N-1,每个小村从 0 到 N-I编号;
- 在测试函数里输入测试组个数 M(1<=M<=500000),再输入 M 行 A、B、C 村的编号;
- 在遍历函数里对每一组给定的 A、B、C 村的编号进行测试,遍历函数采用广度优先遍历法遍历邻接表,判断 C 是否在 A 和 B 之间的路径上,如果 C 在A 和 B 之间的路径上,输出 YES,否则输出 NO。
3、代码
#include<iostream>
using namespace std;
#define MAXNODE 10000 //小村最大个数
int visited[MAXNODE]; //标志数组
typedef struct Edge //边结点
{
int index; //顶点在顶点数组中的位置
struct Edge* nextedge; //指向下一个边结点
}EdgeNode;
typedef struct VNode //顶点信息
{
int data; //顶点数据
EdgeNode* firstedge; //指向第一条边的指针
}Link;
typedef struct //定义邻接表
{
int vertexnum, edgenum;//总顶点数和总边数
Link vertics[MAXNODE]; //顶点数组
}Graph;
void CreateGraph(Graph& g)
{//采用邻接表表示法建立无向村落图
cout << "请输入神秘国度中的小村个数N:";
while (true)
{
cin >> g.vertexnum;
while(!cin.good())
{
cin.clear();
cin.sync();
system("COLOR 01");
cout << "莫急,请重新输入:";
cin >> g.vertexnum;
}
if (1 <= g.vertexnum && g.vertexnum <= MAXNODE) break;
system("COLOR 01");
cout << "莫急,请重新输入:";
}
system("COLOR F4");
g.edgenum = g.vertexnum - 1;//道路数是村子数-1
int i;
for (i = 0; i < g.vertexnum; i++)
{
g.vertics[i].data=i; //每个小村从0开始编号
g.vertics[i].firstedge = NULL;
}
cout << "------------------------------------------\n" ;
for (i = 0; i < g.edgenum; i++)
{
int m, n;
cout << "请输入第" << i + 1 << "条道路的两个端点小村的编号:";
while (true)
{
cin >> m >> n;
while (!cin.good())
{
cin.clear();
cin.sync();
system("COLOR 01");
cout << "莫急,请重新输入:";
cin >> m >> n;
}
if (m >= 0 && m < g.vertexnum && n >= 0 && n < g.vertexnum) break;
system("COLOR 01");
cout << "莫急,请重新输入:";
}
system("COLOR F4");
if(i<g.edgenum-1)
cout << "---------------------------\n" ;
EdgeNode* p1 = new Edge; //头插法,先建立一个Edge类型的结点p1
p1->index = n; //将n村的编号赋值给p1的数据域
p1->nextedge = g.vertics[m].firstedge;//将p1的指针域赋为空值
g.vertics[m].firstedge = p1; //将第m个表头结点的指针域指向p1
EdgeNode* p2 = new Edge; //建立无向图
p2->index = m;
p2->nextedge = g.vertics[n].firstedge;
g.vertics[n].firstedge = p2;
}
}
void BfsTree2(Graph g, int C , int B)
{//广度优先遍历邻接表,并查询B是否在C到所有未访问结点的路径上
int k, Q[MAXNODE], front = 0, rear = 0;//使用队列
int i = 0;
EdgeNode* p; //指向边结点的指针
visited[C] = 1; //C村开始所有访问过的村子标志为1
rear = (rear + 1) % MAXNODE; //计算队尾所在位置
Q[rear] = C; //从C村开始
while (front != rear) //判断队空
{
front = (front + 1) % MAXNODE;//计算队头所在位置
k = Q[front];
p = g.vertics[k].firstedge;
while (p != NULL && i != 1) //是否为最后一个边结点
{
if (!visited[p->index]) //结点是否被访问过
{
visited[p->index] = 1;//标记已访问
if (p->index == B) //如果遍历到B
{
cout << " YES 千里姻缘一路牵,一生甜蜜两村间" << endl;
i = 1;
rear = front;
}
if (i == 0)
{
rear = (rear + 1) % MAXNODE;
Q[rear] = p->index;
}
}//访问结束
p = p->nextedge;
} //判断指针为空结束
} //判断队列为空结束
if (i != 1)
cout << " NO 此情可待成追忆,只是当时已惘然" << endl;
}
void BfsTree1(Graph g, int A, int B, int C)
{//广度优先遍历邻接表,并查询C是否在A和B之间的路径上
int k, Q[MAXNODE], front = 0, rear = 0;//使用队列
int i = 0;
EdgeNode* p; //指向边结点的指针
visited[A] = 1; //A村开始所有访问过的村子标志为1
rear = (rear + 1) % MAXNODE; //计算队尾所在位置
Q[rear] = A; //从A村开始
while (front != rear) //判断队空
{
front = (front + 1) % MAXNODE;//计算队头所在位置
k = Q[front];
p = g.vertics[k].firstedge;
while (p != NULL && i != 1) //是否为最后一个边结点
{
if (!visited[p->index]) //结点是否被访问过
{
visited[p->index] = 1;//标记已访问
if (p->index == B) //如果遍历到B
{
cout << " NO 此情可待成追忆,只是当时已惘然" << endl;
i = 1;
front = rear;
}
else
{
if (p->index == C)//如果遍历到C
{
BfsTree2(g, C, B);
i = 1;
front = rear;
}
}
if (i == 0)
{
rear = (rear + 1) % MAXNODE;
Q[rear] = p->index;
}
}//访问结束
p = p->nextedge;
} //判断指针为空结束
} //判断队列为空结束
}
void test(Graph g)
{//测试
int M, i, j;
int test1[MAXNODE], test2[MAXNODE], test3[MAXNODE];//用于存放测试组数据
cout << "------------------------------------------\n";
cout << "请输入测试组个数M:";
while (true)
{
cin >> M;
while (!cin.good())
{
cin.clear();
cin.sync();
system("COLOR 01");
cout << "莫急,请重新输入:";
cin >> M;
}
if (1 <= M && M <= MAXNODE) break;
system("COLOR 01");
cout << "莫急,请重新输入:";
}
system("COLOR F4");
cout << "------------------------------------------\n";
for (i = 0; i < M; i++)
{
cout << "请输入第"<<i+1<<"组要测试的A B C三村的编号:";
while (true)
{
cin >> test1[i] >> test2[i] >> test3[i];
while (!cin.good())
{
cin.clear();
cin.sync();
system("COLOR 01");
cout << "莫急,请重新输入:";
cin >> test1[i] >> test2[i] >> test3[i];
}
if ((test1[i] >= 0 && test1[i] < g.vertexnum) &&
(test2[i] >= 0 && test2[i] < g.vertexnum) &&
(test3[i] >= 0 && test3[i] < g.vertexnum))
break;
system("COLOR 01");
cout << "莫急,请重新输入:";
}
system("COLOR F4");
if(i<M-1)
cout << "---------------------------\n";
}
cout << "------------------------------------------\n";
cout << "测试后的结果为:\n" ;
for (i = 0; i < M; i++)
{
if (test1[i] == test3[i] || test2[i] == test3[i])
cout << " YES 千里姻缘一路牵,一生甜蜜两村间" << endl;
else
{
for (j = 0; j < g.vertexnum; j++)
visited[j] = 0;//所有未访问村子标志为0
BfsTree1(g, test1[i], test2[i], test3[i]);
}
}
}
int main()
{
system("COLOR F4");
cout << " ****** ****** " << endl;
cout << " ********** ********** " << endl;
cout << " ************************* " << endl;
cout << " ***神秘国度的爱情故事**** " << endl;
cout << " ************************* " << endl;
cout << " *********************** " << endl;
cout << " ***************** " << endl;
cout << " ************* " << endl;
cout << " ******* " << endl;
cout << " * " << "\n\n\n";
Graph g;
CreateGraph(g);
test(g);
cout << "\n\n";
system("pause");
return 0;
}