连通图着色问题
沈阳航空航天大学
课程设计报告
课程设计名称:软件综合课程设计课程设计题目:连通图着色问题
院(系):计算机学院
专业:计算机科学与技术
班级:7401104
学号:200704011110
姓名:武林
指导教师:刘香芹
沈阳航空航天大学课程设计报告
目录
1 需求分析 (2)
1.1题目的内容与要求 (2)
1.11题目的内容 (2)
1.12题目的要求 (2)
1.2题目理解与程序解读 (2)
2 总体设计 (4)
2.1数据结构设计 (4)
2.2数据结构类型与函数 (4)
3 详细设计 (6)
3.1子函数流程图 (6)
3..1.1 memset_子函数 (6)
3..1.2sort子函数 (7)
3..1.3 brush_sort子函数 (8)
3.2主程序流程图 (9)
4 调试分析 (10)
4.1调试时遇到的问题 (10)
4.2解决方案 (10)
4.3调试结果及说明 (11)
参考文献 (12)
源程序(清单) (13)
1 需求分析
1.1题目的内容与要求
1.11题目的内容
输入一个无向图到适当的存储结构中,给图上的每一个结点标记一种颜色,在保证任何相邻结点颜色不同的同时,求解出该图所需要的最少颜色数,并给出每个结点的具体颜色。
1.12题目的要求
1)完成系统需求分析;
2)开发工具可以选择C语言或面向对象的C++等;
3)界面友好,操作方便;
4)按照课程设计规范书写课程设计报告。
1.2题目理解与程序解读
本次课设与离散数学当中图的部分有密切的联系,连通图的着色问题,涉及到图的连通性和图的着色问题。当图的结点之间存在通路,则此图是连通的,在此基础之上对他进行着色。
重要之处在于每个进店标记一种颜色,但要求的是相邻的结点要着上不同的颜色,要求所使用的颜色数最少即是所要求的。
解决此题的算法是韦尔奇.鲍威尔的着色理论,算法如下:
(1)将图的结点按照度数的递减顺序进行排列,(这种排列可能不是唯一的,因为有些点有相同的度数)。
(2)用第一种颜色对第一个结点进行着色,并且按排列次序,对于前面着色点不相邻的每一个结点着上同样的颜色。
(3)用第二种颜色对尚未着色的点重复第二个步骤,用第三种颜色继续这种
做法,直到所有的点全部着上色为止。
所以源程序就是对韦尔奇鲍威尔算法演示。首先输入结点个数和边的个数,结点结构体内包含结点编号,度数,结点的颜色和状态。边的结构体当中包含结点结构体变量,用来指示边起始节点和终止结点,同时还包含边的编号。
对输入的图用关联矩阵来表示,对着色的颜色用整型的数字来表示,所以我们规定数字1—5分别表示为红色,黄色,蓝色,绿色和黑色。
初始化颜色为红色,即是为数字1.颜色个数变量初始化为0个。
2 总体设计
2.1数据结构设计
结点和边分别用结构体来存储,结点的结构体为:
typedef struct Node//结点
{
int v;
int deg;
int color;
bool flag;
}Node;
其中v标示结点的编号,deg标示每个结点的度数,color标示对每个结点着上的颜色,flag标示此时结点的状态。这里我们申请最多可以输入50个结点的空间,Node[50]。
边的结构体为:
typedef struct Edge
{
int e0;
Node e1;
Node e2;
}Edge;
这里e0标示边的编号,e1和e2则代表边的起始节点和终止结点。这里我们也申请了最多50条边的空间,Edge[50]。对每个结点的度数进行排序,呈递减顺序,将结点的编号按排好的顺序存放到数组downnote[m]中,这里的m表示输入结点个数的变量。从数组downnote[m]中的第一个元素开始,根据韦尔奇鲍威尔算法对图进行着色,最后确定着色的个数。
2.2数据结构类型与函数
函数名称函数原型功能描述
main void main(void); 系统主程序
inite void inite(int m,int n); 初始化无相连通图
memset_ void memset_(int m,int n);求出关联矩阵以及各点的度数sort void sort(int m,int n); 对度数进行排序
brush_color void brush_color(int m,int n); 进行着色
表2.1 函数列表
3 详细设计
3.1 子函数流程图
3..1.1 memset_子函数
此部分为求关联矩阵表示,以及求出每个结点相应的度数。
开始
初始化关联矩阵数组
从第一个结点开始寻找相邻结点
对所有边循环寻找
如果此结点的编号与边的起始节点或终止结点相同
关联矩阵数组相应位置置1,并且此结点的度数加1
判断下一条边
是否为最后一条边
判断下一个结点
是否为最后一个结点
显示关联矩阵数组,各点的度数
结束
N
Y
Y
Y
N
N
图3.1 memset_函数
3..1.2sort 子函数
此部分是将各个结点的度数按递减的顺序进行排列。
开始
初始化数组downnote[]
以第一个结点为基准点
如果基准点的度数小于第i 个结点的度数,并且它的状态为flase
将第i 个结点重新赋为基准点
是否为最后的结点
将选出的结点的编号送到数组downnote[]中,
并将他的状态改变
是否已经排序完成
显示度数呈递减顺序
结束
Y
Y
Y
N
N
N
图3.2 子函数sort
3..1.3 brush_sort 子函数
此部分是本程序中最重要的部分,即为结点进行着色。
开始
在数组downnote[]的元素对应的度数找
出相应的结点,按递减顺序
从第一个结点开始判断
判断此结点是否着色
对此结点进行第一种颜色的着色
找出与此结点相邻的结点,并将这些结点的
状态该为假
循环所有结点,找出状态为真,且没有着色的结点
这些节点是否相邻
将找出的第一个结点着上刚才的与它不相邻的结点的颜色,并将其余的结点的状态重新改为真
将着色的颜色改为第二种,并将储存的颜色数加1
是否都已经着色完成
显示各点的颜色,并显示颜色个数
结束
判断下一个结点
Y
N
Y
Y
将他们都着上与第一种颜色相同的色
N
N
图3.3子函数brush_color
3.2 主程序流程图
开始
输入结点个数和边的个数
顺序调用初始化子程序、关联矩阵陈程序、排序
程序和着色子程序
再次输入结点和边的个数,以及相应的子程序
是否继续
结束
Y
N
图3..4主函数
4 调试分析
4.1调试时遇到的问题
调试的时候主要遇到一下几个问题:
1:当给度数最大的结点上第一种颜色,并与他不相邻的结点着上相同的颜色,这时在着上色的结点当中出现了相邻的结点之间着上的是相同的颜色。
2:在排序函数中,假如出现了度数相等的情况时,则不能保证将正确的顺序存放到数组downnote中,也就是说有的结点没有存放进去。
3:当输出有几种颜色时,出现了大于5种以上的情况,我们知道韦尔奇鲍威尔算法针对连通图着色最多有5种情况,保证颜色数最少,多于5种的就不符合要求。
4.2解决方案
1:出现这个错误非常严重,因为这不符合本题的根本要求。当给第一个结点上色完成后,对与它不相邻的结点也上同样的颜色,这时就需要在这些不相邻的结点之间也要求彼此不相邻,才能上色,只要出现相邻就要将后者状态改为假,并且不予以着色。
2:针对第二个问题,经过调试发现,没有考虑相等的度数的情况,以至于出现相等就跳过。
首先将相等且度数最大的这些结点存放到数组中,他们之间可以没有顺序,然后度数次之的按同样的方式存储,检查各个结点的状态,如果还有没有存储的结点,这肯定是度数最少的直接存放到数组的末尾。
3:针对第三个问题,我们发现存储颜色个数的变量count_是全局变量,每次运行完保存当前值,下次运行时从当前值开始累加,这就造成颜色数有时候大于5的情况,所以在下次运行之前要将此变量初始化。
4.3调试结果及说明
1. 说明
(1)本程序的运行环境为VC;
(2)进入演示程序后即显示提示信息:
输入结点数m;
输入边数n:
输入第一条边:
输入第二条边:
………
………
输入第n条边:
输入完毕后即显示出关联矩阵,以及度数排列顺序,给点的着色以及有几种颜色。
2.测试结果
当输入3各结点,3条边时,即是三角形这样的简单的例子,各点的度都为2,所以需要上三种颜色。
参考文献
[1] 严蔚敏,吴伟民.《数据结构》(C语言版)[M].北京:清华大学出版,2007年
[2] 朱站立,张选平.《数据结构》[M].西安:西安交通大学出版社,2007年
[3]耿素云,屈婉玲.《离散数学》[M].北京:高等教育出版社,2003年
源程序(清单)
#include
#include "iomanip"
using namespace std;
typedef struct Node//结点
{
int v;//结点号
int deg;//度
int color;//颜色(0表示无色)
bool flag;//是否着色
}Node;
Node node[20];
typedef struct Edge//边
{
int e0;//边号
Node e1;//起始点
Node e2;//终止点
}Edge;
Edge edge[50];
int node_edge[50][50];//关联矩阵
int downnote[20];//排序角标
int count_1=0;//统计颜色
int draw_color=1;//初始颜色
void inite(int m,int n);// 初始化边和结点
void memset_(int m,int n);//设置关联矩阵及各结点的度
void sort(int m,int n);//读书排序
void brush_color(int m,int n);//将各点的度着色
void inite(int m,int n)
{
int i,j,a,b;
for (i=0;i { node[i].v=i; node[i].deg=0; node[i].color=0; node[i].flag=false; } for (j=0;j { cout<<"输入第"< cout<<"第e"< edge[j].e0=j; edge[j].e1.v=a; edge[j].e2.v=b; } } void memset_(int m,int n) { int i,j; for (i=0;i { for (j=0;j { node_edge[i][j]=0; if ((node[i].v==edge[j].e1.v)||(node[i].v==edge[j].e2.v)) { node_edge[i][j]=node_edge[i][j]+1; node[i].deg=node[i].deg+1; } } } cout<<"关联矩阵表示如下:"< for (i=0;i { cout< for (j=0;j cout< } cout<<"各个结点的度数如下:"< for (i=0;i } void sort(int m,int n) { int i,j,temp; for(i=0;i { downnote[i]=0; node[i].flag=true; } j=0; while (j { temp=0; for (i=0;i { if ((node[temp].deg<=node[i].deg)&&(node[i].flag!=false)) {temp=i;} } node[temp].flag=false; downnote[j]=temp; j++; } for (i=0;i { if (node[i].flag!=false) { node[i].flag=false; downnote[m-1]=i; } } cout<<"度数重新排列呈递减顺序:"< for (j=0;j { cout<<"第v"< } } void brush_color(int m,int n) { int i,j,k,p,q,t; for (i=0;i for (i=0;i { for (j=0;j { if (downnote[i]==node[j].v) { if (node[j].color!=0){break;} else { node[j].color=draw_color; for (k=0;k { if(node[j].v==edge[k].e1.v) { q=edge[k].e2.v; node[q].flag=false; } else if (node[j].v==edge[k].e2.v) { q=edge[k].e1.v; node[q].flag=false; } } for (k=0;k { if (node[k].flag==1&&node[k].color==0) { node[k].color=draw_color; for (t=0;t { if (node[k].v==edge[t].e1.v) { q=edge[t].e2.v; if (node[q].flag!=0){node[q].flag=0;} } if (node[k].v==edge[t].e2.v) { q=edge[t].e1.v; if(node[q].flag!=0){node[q].flag=0;} } } for (t=0;t { if (node[t].flag==1&&node[t].color==0) {node[t].color=draw_color;} } } } draw_color=draw_color+1; count_1=count_1+1; } break; } } for (p=0;p {node[p].flag=true;} } cout<<"此图共有"< cout<<"各结点对应的颜色是:"< for (i=0;i { cout<<"第v"< switch(node[i].color) { case 1: cout< break; case 2: cout< break; case 3: cout< break; case 4: cout< break; case 5: cout< break; } } } void main(void) { int m,n;//结点和边 cout<<"输入结点个数:"< cout<<"输入边的个数:"< inite(m,n); memset_(m,n); sort(m,n); brush_color(m,n); char c; bool note=true; while(note) { cout<<"是否继续?是(y)/否(n)"< draw_color=1;count_1=0; switch(c) { case 'y': cout<<"输入结点个数:"< cout<<"输入边的个数:"< inite(m,n); memset_(m,n); sort(m,n); brush_color(m,n); break; case 'n': note=false;break; } } } 课程设计总结: 通过本次课程设计使我更加清楚了自己的水平以及以后要努力的方向。 我的课设的题目是连通图着色问题,根据题目的内容与要求,首先得到的是用结构体作为结点与边的存储结构。并结合韦尔奇鲍威尔算法进行着色。 在本程序学习与构造中,我不但通过程序的编写学习了数据结构的知识,更加对离散数学当中一些知识理解与掌握,同时明白了基本的编程的方法与应该注意的地方,不但使程序没有主观的的错误,同时还要求没有相应地逻辑错误,使程序能够顺利地进行。 在编写程序的过程中要明白程序的好坏是运行的效率如何,所以在编写程序时尽量用简洁的数据结构方法与算法。同时使程序格式清晰与美观。 通过这次课程设计,我知道要想成为一个合格的程序员,除了要有扎实的专业知识外,还要站在客户的立场上,多为客户考虑。在编写程序的时候,一定要养成良好的编程习惯。此外,课设也教会我要有团队精神,不管遇到什么困难,要多和同学讨论,甚至是“争辩”。在此,也感谢老师的悉心指导! 指导教师评语: 指导教师(签字):年月日课程设计成绩