一笔画问题,即欧拉回路问题,最近在算法课上老师留了这个作业,下面将我的实现说一下。首先,先将问题描述一下。
该图中节点编号从上至下,从左至右编号如下
1 2
3 4 5 6
7 8 9 10 11
12 13
14 15 16
要求:从节点1开始,一笔将该图形画出。
首先讲下该题的大概思路:
概括的讲是先找小回路,再并小回路。
(1)先将1放入访问队列中,寻找1的未访问过的邻接边,将满足这样条件的边中另一顶点值最小的顶点放入访问队列中,再从这个点出发继续寻找,直至找到的变的另一顶点与队列头部顶点相等(这时说明找到了一条小回路),将找到的第一个小回路的边标记为1;若队列头顶点还存在另一小回路,则继续寻找另一小回路;否则要将队列头结点删除,开始下一点的查找。
(2)将图中所有边都标记后,再从1开始,找与该点邻接的边中值最大的边的另一点,若存在多个边值一样的边,则先从顶点值较小的点开始,并将当前访问的点设置为该点,再往下找。
说了这么多,还是感觉不大明白。用本题的具体数字说明一下。
第一次找小回路1-3-4-1
第二次3-7-8-3
第三次4-8-9-4
第四次9-5-2-6-5-10-6-11-10-9
。。。。。。
在访问队列中存储的节点
1,3,4,7,8,9,5,2,6,10,11,12,13,14,15,16
#include<queue>
#include<iostream>
#include<fstream>
#include<string>
#define MAX 1000
using namespace std;
int main(){
ifstream fin("input2.txt");
ofstream fout("output.txt");
int m,n,start,end;
int i,j;
int now,front;
int flag = 1;//边的标记
int count = 2;
int cycleSt = 1;//一笔画的起点
int cycleEnd = 1;//一笔画的终点
int minNode=9999;
int maxEdge = 0;
fin>>m>>n;//m:图中点数,n:输入文件数据行数
int **edge = new int*[m+1];//图的连通二维数组表示
for(i=0;i<m+1;i++)
edge[i] = new int[m+1];
bool *inQueue = new bool[m+1];//图中顶点的访问队列标记,
//若之前该顶点已放入队列中,那么该顶点标记为true
//若该顶点从未放入队列中,那么该顶点标记为false
for(i=1;i<m+1;i++)
inQueue[i]=false;
//初始化连通图,值为MAX则说明未连通
for(i=0;i<m+1;i++)
for(j=0;j<m+1;j++)
edge[i][j]=MAX;
queue<int> q;//顶点访问队列
fin>>start>>end;
q.push(start);//先将起始点放入访问队列中
edge[end][start]=edge[start][end]=0;
while(count<=n){
fin>>start>>end;
edge[start][end]=edge[end][start]=0;
count++;
}
front = q.front();//小回路的起点
now = q.front();//目前正在访问的点
inQueue[now]=true;//把起点标记为true,表示已放入过队列
do{
for(i=1;i<m+1;i++){
if(edge[now][i]==0){//如果与起点邻接的某边未走过
edge[i][now]=edge[now][i]=flag;//标记该边
if(i!=front&&!inQueue[i]){
q.push(i);//把与该边邻接的另一顶点放入队列
inQueue[i] = true;//将该点放入过队列的标记设置为true
}
now = i;//下一步开始从这一点出发
break;
}
}
if(i==m+1){//如果某个点相邻接的边都访问过,那么将该点从访问队列中删除,并访问下一个点
cout<<front<<" ";
q.pop();
if(!q.empty()){
now = q.front();
front = q.front();
}
}
else if(now==front){//如果现在访问的点是小回路的起点
//首先查看该回路是否有其他的回路存在
for(i=1;i<m+1;i++){
if(edge[now][i]==0)break;
}
//没有其他未访问的边了,删除头结点,访问下一结点,并将边标记加1
if(i==m+1){
cout<<front<<" ";
q.pop();
if(!q.empty()){
now=q.front();
inQueue[now]=true;
front = q.front();
}
flag++;
}else{//若还有其他未访问的边,则将边标记加1后,走新的小回路
now = front;
flag++;
}
}
}while(!q.empty());
/*for(i=1;i<m+1;i++)
for(j=1;j<m+1;j++)
fout<<edge[i][j]<<" ";
fout<<endl;*/
now = cycleSt;
cout<<"一笔画的路线是:"<<endl<<now<<"->";
while(true){
maxEdge = 0;
minNode = 9999;
for(i=1;i<m+1;i++){
//在边标记不同的情况下,找表标记最大的边的邻接点
//在边标记相同的情况下,找节点值最小的邻接点
if(edge[now][i]>maxEdge&&edge[now][i]!=MAX){
maxEdge = edge[now][i];
//edge[i][now]=edge[now][i]=MAX;
minNode = i;
//break;
}
}
if(minNode==9999){
cout<<"未能找到一笔画路线"<<endl;
break;
}else{
edge[minNode][now]=edge[now][minNode]=MAX;//访问后,将连通边设置为不连通
now = minNode;
if(now==cycleEnd) {cout<<now;break;}//如果起点和终点相等,则退出循环
else cout<<now<<"->";
}
}
return 0;
}
呵呵,讲的可能不是很清楚,有不懂的可以问我,希望大家可以在这探讨,源程序及输入文件见压缩包附件。
PS:感谢杨老师的算法课,这位老教授的课很有趣,我也收获了很多。
- 大小: 9.1 KB
分享到:
相关推荐
在这个特殊的实现中,游戏是使用C++编程语言编写的,并且结合了Microsoft Foundation Classes (MFC)库来构建用户界面。MFC是微软为Windows应用程序开发提供的一套C++类库,它简化了Windows API的使用。 在这款...
一笔画问题,也被称为欧拉路径问题,是图论中...通过C++实现,我们可以利用面向对象编程的优势,将问题分解为独立的类和方法,使得代码易于理解和维护。在实际编程时,要注重代码的可读性和效率,遵循良好的编程规范。
本项目基于Qt实现了一款一笔画游戏,这种游戏通常要求玩家在一张网格上用一笔连接所有的点,且不能重复经过任何线段。下面将详细解析该项目的源码和实现机制。 首先,我们来看项目的解决方案文件`OneStroke.sln`,...
一笔画游戏,也称为欧拉路径问题,是经典的逻辑谜题,玩家需要从起点开始,沿着图形的边,不重复任何边,最后回到起点,完成整个图形的绘制。这种游戏挑战了玩家的空间想象和逻辑思维能力,而在OneTouchDraw的帮助下...
在编程实现中,这通常涉及到图论中的连通性问题。开发者可能使用邻接矩阵或邻接表来表示游戏板,并通过深度优先搜索(DFS)或广度优先搜索(BFS)等算法来检查是否能一笔画完所有节点。 标签“Qt”再次强调了这款...
4. **算法与数据结构**:解决一笔画问题可能需要用到图论中的算法,如深度优先搜索(DFS)或广度优先搜索(BFS),以及路径规划。 5. **事件处理**:游戏需要响应用户的触摸、点击等操作,这涉及事件监听和处理机制...
本书以流行的面试题讲解为主要内容,介绍了C、C++语言基本概念,包括保留字、字符串、指针和引用、结构体、库函数等各个方面的基础知识,介绍了面向对象编程基本概念,包括如何实现继承、多态和封装等。还介绍了排序...
本文将深入探讨如何使用Visual C++(简称VC)来实现一笔画出金刚石、魔术三角和递归圆这三个有趣的图形。首先,我们要明白这涉及到的基本概念和编程技术。 **一笔画算法(一笔连通图)** 一笔画问题源于图论,指的...
【算法实现】Hierholzer算法的C++实现包括一个dfs()函数,用于递归遍历图,以及主函数main()中读取图的输入并调用dfs()。这里使用了栈q来存储答案队列,确保了路径的正确输出。 总的来说,图论中的一笔画问题和相关...
"中国邮递员问题" 中国邮递员问题(CPP)是一个著名的图论问题,旨在寻找一条可能短的路线,使邮递员从邮局出发,经过所有街道至少一次后返回邮局。这个问题是中国数学家管梅谷在1962年首先提出的。 问题描述 ...
15. **其他题目**:包括排球队员站位问题、自然数分解问题、马的遍历、加法分式分解、地图着色、放置长条块、最短路径、火车调度、农夫过河、七段数码管问题、数字不连续问题、棋子移动问题、一笔画问题、城市遍历、...
快速排序的伪代码和C++实现如下: ```cpp // 快速排序的分割函数 int partition(int arr[], int low, int high) { // ... } // 快速排序函数 void quickSort(int arr[], int low, int high) { // ... } // ...
在图形学中,我们可能使用编程语言如C++或Python,结合OpenGL或DirectX等图形库来实现这样的画法。通过设置合适的顶点坐标并绘制线条,我们可以创建出各种形状和尺寸的菱形。 其次,“奇数一笔画”是一个与图论和...
2. **一笔画问题**:这是典型的图论问题,要求寻找一笔画路径。对于特定的图形,可以通过观察和尝试找到解决方案。 3. **开关状态问题**:这个问题涉及到数学中的平方根的概念。最终处于关闭状态的灯是那些编号为...
C++实现如下: ```cpp int findClosestPair(int arr[], int n) { int min_diff = INT_MAX; int pair1 = 0, pair2 = 1; for (int i = 0; i ; i++) for (int j = i+1; j ; j++) if (abs(arr[i] - arr[j]) ) {...
以下是C++实现: ```cpp void quicksort(int arr[], int low, int high); int partions(int arr[], int low, int high); int main(){ int a[] = {...}; int n = sizeof(a) / sizeof(a[0]); quicksort(a, 0, ...
以下是C++实现: ```cpp #include void quicksort(int a[], int low, int high); int partions(int a[], int low, int high); int main() { int a[] = { ... }; // 初始化数组 int n = sizeof(a) / sizeof(a[0]...
C++代码实现: ```cpp int main() { double value = 0; for (int n = 1; n ; ++n) { value = value * 10 + 1; if (value % 2013 == 0) { cout 至少为:" ; break; } } } ``` 5. **计算π值**:π值的...
在编程实现时,一般会选用一种高级图形库,如OpenGL、DirectX或更简单的2D图形库如pygame(Python)或GDI+(C++)。这些库提供了绘制线条、填充图形和设置颜色等功能。在我们的例子中,我们可能会选择一个简单的方法...