用回溯法求解图的m着色问题
回溯法实验(图的m着色问题)

算法分析与设计实验报告第六次附加实验cout<<endl;}elsefor(int i=1;i<=m;i++){x[t]=i;if(ok(t)) Backtrack(t+1);//回溯,继续寻找下一层x[t]=0;//回到最初状态,使x[1]继续尝试其他填色的可能解}}测试结果当输入图如下时:结果如下:12435只要输入边即可当输入的图如下时:结果如下:附录:完整代码(回溯法)//图的m着色问题回溯法求解#include<iostream>using namespace std;class Color{friend void mColoring(int,int,int **);private:bool ok(int k);void Backtrack(int t);int n, //图的顶点个数m, //可用颜色数**a, //图的邻接矩阵*x; //当前解long sum; //当前已找到的可m着色的方案数};bool Color::ok(int k) //检查颜色可用性{for(int j=1;j<=n;j++)if((a[k][j]==1)&&(x[j]==x[k])) //两个点之间有约束且颜色相同return false;return true;}void Color::Backtrack(int t){if(t>n) //到达叶子节点{sum++; //可行解+1cout<<"着色: ";for(int i=1;i<=n;i++) //输出可行解方案cout<<x[i]<<" ";cout<<endl;}elsefor(int i=1;i<=m;i++){x[t]=i;if(ok(t)) Backtrack(t+1);//回溯,继续寻找下一层x[t]=0;//回到最初状态,使x[1]继续尝试其他填色的可能解 }}void mColoring(int n,int m,int **a){Color X;//初始化XX.n=n;X.m=m;X.a=a;X.sum=0;int *p=new int[n+1];for(int i=0;i<=n;i++)p[i]=0;X.x=p;cout<<"顶点: ";for(int i=1;i<=n;i++) //用于输出结果cout<<i<<" " ;cout<<endl;X.Backtrack(1); //从顶点1开始回溯delete []p;cout<<"解法个数:"<<X.sum<<endl;}int main(){int n;int m;cout<<"please input number of node:";cin>>n;cout<<"please input number of color:";cin>>m;int **a=new int*[n+1];for(int i=0;i<=n;i++)a[i]=new int[n+1];for(int i=0;i<=n;i++) //利用抽象图实现图的邻接矩阵for(int j=0;j<=n;j++)a[i][j]=0;int edge;cout<<"please input adjacent edge number:";cin>>edge;int v,w;cout<<"please inout adjacent edge:"<<endl; //只要输入边即可for(int i=0;i<edge;i++){cin>>v>>w; //由于是无向图,所以对应的邻接矩阵对应的边都有,即v->m,m->v都有边a[v][w]=1;a[w][v]=1;}mColoring(n,m,a);system("pause");return 0;}。
图的着色问题--C++实现(含详细注释)

图的着色问题一、题目简述(1) 图的m-着色判定问题给定一个无向连通图 G 和 m 种不同的颜色。
用这些颜色为图 G 的各顶点着色,每个顶点着一种颜色,是否有一种着色法使 G 中任意相邻的两个顶点着不同颜色?(2) 图的m-着色优化问题若一个图最少需要 m 种颜色才能使图中任意相邻的两个顶点着不同颜色,则称这个数 m 为该图的色数。
求一个图的最小色数 m 的问题称为m-着色优化问题。
二、算法思想1. m-着色判定问题总体思想:通过回溯的方法,不断为每一个节点着色,每个点的颜色由一个数字代表,初始值为1。
在对前面 step - 1 个节点都合法的着色之后,开始对第 step 个节点进行着色。
如果 n 个点均合法,且颜色数没有达到 m 种,则代表存在一种着色法使 G中任意相邻的两个顶点着不同颜色。
具体步骤:1. 对每个点 step ,有 m 种着色可能性,初始颜色值为1。
2. 检查第 step 个节点颜色的可行性,若与某个已着色的点相连且颜色相同,则不选择这种着色方案,并让颜色值加1,继续检查该点下一种颜色的可行性。
3. 如果第 step 点颜色值小于等于 m ,且未到达最后一个点,则进行对第 step + 1 点的判断。
4. 如果第 step 点颜色值大于 m ,代表该点找不到合适的分配方法。
此时算法进行回溯,首先令第 step 节点的颜色值为0,并对第 step - 1 个点的颜色值+1后重新判断。
5. 如果找到一种颜色使得第 step 个节点能够着色,说明 m 种颜色的方案是可行的。
6. 重复步骤2至5,如果最终 step 为0则代表无解。
2. m-着色优化问题基于问题1,对于一个无向图 G ,从1开始枚举染色数,上限为顶点数,第一个满足条件的颜色数即为所求解。
三、实现过程(附代码)1. m-着色判定问题#include<iostream>using namespace std;int color[100]; // 每个点的颜色int mp[100][100]; // 图的邻接矩阵int n, m, x; // n顶点,m种颜色方案,x条边bool check(int step) {// 判断与step点相邻的点,颜色是否与step点相同,若相同则返回falsefor (int i=1; i<=n; i++) {if (mp[step][i] ==1&&color[i] ==color[step]) {return false;}}return true;}bool Solve(int m) {// 求解是否可以找到一种可行的染色方案int step=1; // step指示当前节点while (step>=1) {color[step] +=1; // 假定颜色值从1开始,若为回溯,选择下一种方案while (color[step] <=m) { // 按照问题条件选择第step点颜色if (check(step)) {break;} else {color[step]++; // 搜索下一个颜色}}if (color[step] <=m&&step==n) { // 如果找完n个点,且染色方法小于等于m种 return true;} else if (color[step] <=m&&step<n) {step++; // 求解下一个顶点} else { // 如果染色数大于m个,回溯color[step] =0; // 回溯,该点找不到合适的分配方法,对上一点进行分析step--;}}// 如果step退到0,则代表无解return false;}int main() {int i, j;bool ans=false;cout<<"输入顶点数n和着色数m"<<endl;cin>>n>>m;cout<<"输入边数"<<endl;cin>>x;cout<<"具体输入每条边"<<endl;for (int p=0; p<x; p++) { // 以无向邻接矩阵存储边cin>>i>>j;mp[i][j] =1;mp[j][i] =1;}if (Solve(m)) {cout<<"有解";} else {cout<<"无解";}return0;}2. m-着色优化问题#include<iostream>using namespace std;int color[100]; // 每个点的颜色int mp[100][100]; // 图的邻接矩阵int n, m, x; // n顶点,m种颜色方案,x条边bool check(int step) {// 判断与step点相邻的点,颜色是否与step点相同,若相同则返回falsefor (int i=1; i<=n; i++) {if (mp[step][i] ==1&&color[i] ==color[step]) {return false;}}return true;}bool Solve(int m) {// 求解是否可以找到一种可行的染色方案int step=1; // step指示当前节点while (step>=1) {color[step] +=1; // 假定颜色值从1开始,若为回溯,选择下一种方案while (color[step] <=m) { // 按照问题条件选择第step点颜色if (check(step)) {break;} else {color[step]++; // 搜索下一个颜色}}if (color[step] <=m&&step==n) { // 如果找完n个点,且染色方法小于等于m种 return true;} else if (color[step] <=m&&step<n) {step++; // 求解下一个顶点} else { // 如果染色数大于m个,回溯color[step] =0; // 回溯,该点找不到合适的分配方法,对上一点进行分析step--;}}// 如果step退到0,则代表无解return false;}int main() {int i, j;bool ans=false;cout<<"输入顶点数n"<<endl;cin>>n;cout<<"输入边数"<<endl;cin>>x;cout<<"具体输入每条边"<<endl;for (int p=0; p<x; p++) { // 以无向图邻接矩阵存储边 cin>>i>>j;mp[i][j] =1;mp[j][i] =1;}for (m=1; m<=n; m++) { // 从小到大枚举着色数mif (Solve(m)) { // 如果有解,输出答案并跳出循环cout<<"最小色数m为 "<<m;break;}}return0;}四、结果及分析问题1测试用例:问题2测试用例:经检验,最少着色数的范围为2-4,意味着使 G 中任意相邻的两个顶点着不同颜色最多需要4种颜色。
涂色问题的常见解法及策略

涂色问题的常见解法及策略涂色问题是在给定一定数量的图形或区域的情况下,选择不同的颜色对它们进行涂色,使得相邻的区域具有不同的颜色。
这个问题在计算机图像处理、地图着色、图论等领域都有广泛的应用。
本文将介绍常见的涂色问题解法及策略。
1. 回溯法回溯法是一种常见的解决涂色问题的策略。
其基本思想是尝试在每个区域上涂上一种颜色,并检查该颜色是否符合要求。
如果符合要求,则继续涂色下一个区域;如果不符合要求,则回溯到上一个区域重新选择颜色。
回溯法的算法步骤如下:1.选择一个起始区域。
2.在该区域上选择一种颜色,并检查是否与相邻区域的颜色冲突。
3.如果颜色冲突,则选择另一种颜色,并重新检查。
4.如果所有颜色都冲突,则回溯到上一个区域重新选择颜色。
5.重复步骤2-4,直到所有区域都被涂色。
回溯法的优点是简单易懂,容易实现。
但对于复杂的问题,可能会产生大量的重复计算,效率较低。
为了提高效率,可以采用剪枝或启发式搜索等技巧进行优化。
2. 图着色算法涂色问题可以看作是图着色问题的特例,其中每个区域可以看作是一个节点,相邻的区域之间有一条边。
因此,可以借用图着色算法来解决涂色问题。
图着色算法的基本思想是为每个节点选择一个颜色,并确保相邻节点具有不同的颜色。
常见的图着色算法有贪心算法、回溯法、禁忌搜索等。
其中,贪心算法是一种简单且高效的图着色算法。
其基本思想是每次选择一个颜色,并将其分配给当前节点,然后继续处理下一个节点。
在选择颜色时,优先选择与当前节点相邻节点颜色不同的颜色。
贪心算法的流程如下:1.对节点进行排序,按照节点的度从大到小排序。
2.依次处理每个节点,选择一个颜色,并将其分配给当前节点。
3.检查相邻节点的颜色,如果与当前节点的颜色相同,则选择另一种颜色,并重新检查。
4.重复步骤2-3,直到所有节点都被着色。
贪心算法的优点是简单高效,适用于大规模的问题。
然而,由于贪心算法的局部最优性,可能无法得到全局最优解。
3. 深度优先搜索深度优先搜索是一种常见的解决涂色问题的策略。
算法设计与分析复习题目及答案

一。
选择题1、二分搜索算法是利用( A )实现的算法。
A、分治策略B、动态规划法C、贪心法D、回溯法2、下列不是动态规划算法基本步骤的是( B )。
A、找出最优解的性质B、构造最优解C、算出最优解D、定义最优解3、最大效益优先是( A )的一搜索方式。
A、分支界限法B、动态规划法C、贪心法D、回溯法4、在下列算法中有时找不到问题解的是( B )。
A、蒙特卡罗算法B、拉斯维加斯算法C、舍伍德算法D、数值概率算法5. 回溯法解旅行售货员问题时的解空间树是( B )。
A、子集树B、排列树C、深度优先生成树D、广度优先生成树6.下列算法中通常以自底向上的方式求解最优解的是( B )。
A、备忘录法B、动态规划法C、贪心法D、回溯法7、衡量一个算法好坏的标准是(C )。
A 运行速度快B 占用空间少C 时间复杂度低D 代码短8、以下不可以使用分治法求解的是(D )。
A 棋盘覆盖问题B 选择问题C 归并排序D 0/1背包问题9. 实现循环赛日程表利用的算法是( A )。
A、分治策略B、动态规划法C、贪心法D、回溯法10、下列随机算法中运行时有时候成功有时候失败的是(C )A 数值概率算法B 舍伍德算法C 拉斯维加斯算法D 蒙特卡罗算法11.下面不是分支界限法搜索方式的是( D )。
A、广度优先B、最小耗费优先C、最大效益优先D、深度优先12.下列算法中通常以深度优先方式系统搜索问题解的是( D )。
A、备忘录法B、动态规划法C、贪心法D、回溯法13.备忘录方法是那种算法的变形。
( B )A、分治法B、动态规划法C、贪心法D、回溯法14.哈弗曼编码的贪心算法所需的计算时间为( B )。
A、O(n2n)B、O(nlogn)C、O(2n)D、O(n)15.分支限界法解最大团问题时,活结点表的组织形式是( B )。
A、最小堆B、最大堆C、栈D、数组16.最长公共子序列算法利用的算法是( B )。
A、分支界限法B、动态规划法C、贪心法D、回溯法17.实现棋盘覆盖算法利用的算法是( A )。
图的着色问题

问题来源
图的着色
通常所说的着色问题是指下述两类问题: 通常所说的着色问题是指下述两类问题: 1.给定无环图G=(V,E),用m种颜色为图中 的每条边着色,要求每条边着一种颜色, 的每条边着色,要求每条边着一种颜色,并 使相邻两条边有着不同的颜色, 使相邻两条边有着不同的颜色,这个问题称 为图的边着色问题。 为图的边着色问题。 2.给定无向图G=(V,E),用m种颜色为图中 的每个顶点着色,要求每个顶点着一种颜色, 的每个顶点着色,要求每个顶点着一种颜色, 并使相邻两顶点之间有着不同的颜色, 并使相邻两顶点之间有着不同的颜色,这个 问题称为图的顶着色问题。 问题称为图的顶着色问题。
化简得
( a + bd )(b + aceg )(c + bdef )( d + aceg )(e + bcdf )( f + ceg )( g + bdf )
求极小覆盖法- 求极小覆盖法-布尔代数法
Step3:从中挑选所用极大独立集个数最小者, Step3:从中挑选所用极大独立集个数最小者, 即为X 即为X(G) 但上述子集的颜色数都不是X ),正确的应 但上述子集的颜色数都不是X(G),正确的应 该是X =3,该子集为: {b,d,f}中的 该是X(G)=3,该子集为:给{b,d,f}中的 b,d,f涂颜色 涂颜色1 {a,e,g}中a,e,g涂颜色 涂颜色2 b,d,f涂颜色1,为{a,e,g}中a,e,g涂颜色2为 {a,c,g}中的 涂颜色3 中的c {a,c,g}中的c涂颜色3。 由此可见, 由此可见,求色数其需要求极大独立集以 及一切若干极大独立集的和含所有顶点的子 对于大图, 集,对于大图,因为图计算量过大而成为实 际上难以凑效的算法,所以不是一个好算法, 际上难以凑效的算法,所以不是一个好算法, 一般我们采用贪心法等近似算法来求解 。
0030算法笔记——最大团问题和图的m着色问题

3if (OK)// 进入左子树 3{ 33x[i] = 1; 33cn++; 33Backtrack(i+1); 33x[i] = 0; 33cn--; 3}
if (cn + n - i >= bestn)// 进入右子树 3{ 33x[i] = 0; 33Backtrack(i+1); 3} }
3333 如果U∈V且对任意u,v∈U有(u, v)不属于E,则称U是G的空子图。G的空子图U是G的独立集当且仅当U不包 含在G的更大的空子图中。G的最大独立集是G中所含顶点数最多的独立集。
3333 对于任一无向图G=(V, E),其补图G'=(V', E')定义为:V'=V,且(u, v)∈E'当且仅当(u, v)∈E。 3333 如果U是G的完全子图,则它也是G'的空子图,反之亦然。因此,G的团与G'的独立集之间存在一一对应的 关系。特殊地,U是G的最大团当且仅当U是G'的最大独立集。
深度优先搜索与回溯算法

8、字符序列(characts) 【问题描述】 从三个元素的集合[A,B,C]中选取元素生成一个N个字符组成的序列,使 得没有两个相邻字的子序列(子序列长度=2)相同。例:N = 5时ABCBA是合 格的,而序列ABCBC与ABABC是不合格的,因为其中子序列BC,AB是相同的。 对于由键盘输入的N(1<=N<=12),求出满足条件的N个字符的所有序列和其 总数。 【输入样例】 4 【输出样例】
72
•9、试卷批分(grade) •【问题描述】
•某学校进行了一次英语考试,共有10道是非题,每题为10分,解答用1表示“是”, 用0表示“非”的方式。但老师批完卷后,发现漏批了一张试卷,而且标准答案也丢 失了,手头只剩下了3张标有分数的试卷。
•试卷一:① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩
•0 0 1 0 1 0 0 1 0 0 得分:70
【例6】数的划分(NOIP2001) 【问题描述】 将整数n分成k份,且每份不能为空,任意两种分法不能相同 (不考虑顺序)。例如:n=7,k=3,下面三种分法被认为是相同的。 • 1,1,5; 1,5,1; 5,1,1; • 问有多少种不同的分法。 • 【输入格式】 • n,k (6<n≤200,2≤k≤6) • 【输出格式】 • 一个整数,即不同的分法。 • 【输入样例】 • 7 3 • 【输出样例】 • 4 { 4种分法为:1,1,5;1,2,4;1,3,3; 2,2,3 说明部分不必输出 }
【课堂练习】
1、输出自然数1到n所有不重复的排列,即n的全排列。 【参考过程】 int Search(int i) { Int j; for (j=1;j<=n;j++) if (b[j]) { a[i]=j; b[j]=false; if (I<n) Search(i+1); else print(); b[j]=true; } }
回溯问题:m点着色、n皇后、tsp递归迭代算法

m着色回溯法递归//输入n为顶点个数,颜色数m,图的邻接矩阵c[][]//输出n个顶点的着色x[]//递归方法求解#include <iostream>using namespace std;bool c[6][6];int x[6];int m=3;int n=5;bool ok(int k) //判断对顶点k着色以后是否合法着色{int i;for(i = 1; i < k; i++)if((c[k][i]==1 && x[k] ==x[i]))return false;return true;}void output(int x[]){cout<<"The feasibleresult is:"<<endl;for(int i=1;i<=n;i++)c out<<x[i]<<' ';cout<<endl;return;}void backtrack (int t){if (t>n) output(x);elsefor (int i=1;i<=m;i++) {x[t]=i;if (ok(t)) backtrack(t+1);x[t]=0;}}int main(){int i, j;for(i = 1; i < 5; i++)for(j = 1; j < 5;j++)c[i][j] = false;c[1][2] = true;c[1][3] = true;c[2][3] = true;c[2][4] = true;c[2][5] = true;c[3][5] = true;c[4][5] = true;c[2][1] = true;c[3][1] = true;c[3][2] = true;c[4][2] = true;c[5][2] = true;c[5][3] = true;c[5][4] = true;backtrack(1);cout << endl;return 0;}m着色回溯法迭代//输入n为顶点个数,颜色数m,图的邻接矩阵c[][]//输出n个顶点的着色x[]//第一个结点也可以有m种着色方案#include <iostream>using namespace std;bool c[6][6];int x[6];int m=3;int n=5;bool ok(int k) //判断对顶点k着色以后是否合法着色{int i;for(i = 1; i < k; i++)if((c[k][i]==1 && x[k] ==x[i]))return false;return true;}void m_coloring(int n, int m){int i, k;for(i = 1; i <= n; i++)x[i] = 0;k =1;while(k >=1){x[k]++;while(x[k] <= m)if( ok(k)==1) break;else x[k]++;if(x[k] <= m &&k==n){for(i=1;i<=n;i++)cout<<x[i]<<" ";cout<<endl;k--;//return;如果只需要一个解可以将上两句去掉,加入返回语句}else if(x[k]<=m&&k<n)k++;else{x[k]=0;k--;}}}int main(){int i, j;for(i = 1; i < 5; i++)for(j = 1; j < 5;j++)c[i][j] = false;c[1][2] = true;c[1][3] = true;c[2][3] = true;c[2][4] = true;c[2][5] = true;c[3][5] = true;c[4][5] = true;c[2][1] = true;c[3][1] = true;c[3][2] = true;c[4][2] = true;c[5][2] = true;c[5][3] = true;c[5][4] = true;m_coloring(5, 3);cout << endl;return 0;}//递归方法求解n皇后问题#include <iostream>using namespace std;#define Q_num 4int x[Q_num]; //存放每行棋子位置int number=0; //存放棋盘解的个数void output(int x[]){cout<<"棋盘放置位置如图:"<<endl;for(inti=1;i<=Q_num;i++){for(intj=1;j<=Q_num;j++){if(j==x[i])printf("%3d",x[i]);elseprintf("%3d",0);}cout<<endl;}cout<<endl;}bool Place(int k) //考察皇后k放置在x[k]列是否发生冲突{for (int i=1; i<k; i++)i f (x[k]==x[i] ||abs(k-i)==abs(x[k]-x[i]))return false;r eturn true;}int Queue_backtrack(int t){if (t>Q_num) {number++;output(x);}elsefor (inti=1;i<=Q_num;i++) {x[t]=i;if (x[t] <= Q_num&& Place(t))Queue_backtrack(t+1);x[t]=0;}returnnumber;}int main(){int i;for(i = 1; i <=Q_num;i++)x[i] = 0;cout<<"共有解:"<<Queue_backtrack(1)<<"个"<<endl;cout << endl;return 0;}//回溯法迭代求解n皇后问题#include <iostream>using namespace std;#define Q_num 8int x[Q_num]; //存放每行棋子位置int number=0; //存放棋盘解的个数void output(int x[]){for(inti=1;i<=Q_num;i++){for(intj=1;j<=Q_num;j++){if(j==x[i])printf("%3d",x[i]);elseprintf("%3d",0);}cout<<endl;}cout<<endl;return;}bool Place(int k) //考察皇后k放置在x[k]列是否发生冲突{for (int i=1; i<k; i++)i f (x[k]==x[i] ||abs(k-i)==abs(x[k]-x[i]))return false;r eturn true;}int Queue(int n){int i, k;for(i =0; i <= n; i++)x[i] = 0;k =1;while(k >=1){x[k]++;while(x[k] <= n&& !Place(k))x[k]++;i f(x[k] <= n &&k==n){number++;cout<<"棋盘放置具体位置如图:"<<endl<<endl;output(x);//return;如果只需要一个解}e lse if (x[k]<=n&& k<n)k++;else{x[k]=0;k--;}}return number; }int main(){cout<<"共有"<<Queue(Q_num)<<"个解"<<endl;return 0;}//递归方法实现哈密顿回路问题//指定一个城市为出发城市#include <string.h>#include <iostream>using namespace std;bool c[6][6];int x[6];int n=5;void output(int x[]){for(int i=1;i<=n;i++)c out<<x[i]<<' ';cout<<endl;return;}void hamilton(int k ){if(k>n && c[x[k-1]][1]==1)output(x);elsef or(int i=k;i<=n;i++){swap(x[k],x[i]);if ( c[x[k-1]][x[k]]==1)hamilton(k+1);swap(x[i],x[k]);}}int main(){int n = 5;memset(c, 0, sizeof(c));c[1][2] = true;c[2][1] = true;c[1][4] = true;c[4][1] = true;c[2][4] = true;c[4][2] = true;c[2][3] = true;c[3][2] = true;c[3][5] = true;c[5][3] = true;c[4][5] = true;c[5][4] = true;c[2][5] = true;c[5][2] = true;c[3][4] = true;c[4][3] = true;for(int i = 0; i <= n;i++){x[i] = i;}hamilton(2);//默认以第一个城市开始,搜索解空间树(子集树形式)直接从第二层开始//如果出发城市也可任选,则需要将c[0][i]=1,i=1~n,此时调用hamilton(1)即可cout << endl;return 0;}//哈密顿回路问题回溯法,解空间树按子集树构造,//采用迭代法实现//起始结点(出发城市)默认以第一个开始#include <string.h>#include <iostream>using namespace std;void hamilton(int n, int x[], boolc[6][6]){int i, k;bool*visited = new bool[n+1];for(i = 1; i <= n; i++){x[i] = 0;visited[i] = false;}visited[1]=1;x[1]=1;//默认以第一个城市开始k =2; //搜索解空间树(子集树形式)直接从第二层开始while(k >1){x[k]++;while(x[k] <= n)if(visited[x[k]]==0 &&c[x[k - 1]][x[k]]==1)break;elsex[k]++;if(x[k] <= n && k==n&& c[x[k]][1]==1){f or(k=1;k<=n;k++)cout<<x[k]<<' ';cout<<endl;k--;// break;输出一个解结束时用他替代上两句}else if(x[k]<=n &&k<n)//k!=n-1){v isited[x[k]]=1;k++;}else{x[k]=0;k--;visited[x[k]]=0;}}delete []visited; }int main(){int n = 5;bool c[6][6];memset(c, 0, sizeof(c));c[1][2] = true;c[2][1] = true;c[1][4] = true;c[4][1] = true;c[2][4] = true;c[4][2] = true;c[2][3] = true;c[3][2] = true;c[3][5] = true;c[5][3] = true;c[4][5] = true;c[5][4] = true;c[2][5] = true;c[5][2] = true;c[3][4] = true;c[4][3] = true;int x[6];hamilton(5, x, c);cout << endl;return 0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验二用回溯法求解图的m着色问题
一、实验目的
1、掌握回溯法求解问题的一般特征和步骤
2、使用回溯法编程求解图的m着色问题。
二、实验原理
回溯法是一个既带有系统性又带有跳跃性的的搜索算法。
回溯法在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任何一个结点时,总是先判断该结点是否肯定不包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树搜索。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可结束。
回溯法从开始结点(根结点)出发,以深度优先搜索的方式搜索整个解空间。
这个开始结点就成为一个活结点,同时也成为当前的扩展结点。
在当前的扩展结点处,搜索向纵深方向移至一个新结点。
这个新结点就成为一个新的活结点,并成为当前扩展结点。
如果在当前的扩展结点处不能再向纵深方向移动,则当前的扩展结点就成为死结点。
此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。
回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已无活结点时为止。
三、问题描述
给定一个无向连通图G和m种不同的颜色。
用这些颜色为图G的各顶点着色,每个顶点着一种颜色。
若一个图最少需要m种颜色才能使图中任何一条边连接的2个顶点着有不同的颜色,则称这个数m为该图的色数。
求一个图的色数m的问题称为图的m可着色优化问题。
设计一个算法,找出用m种颜色对一个图进行着色的不同方案。
四、算法设计与分析
用邻接矩阵a来表示一个无向连通图G=(V,E)。
用整数1,2,…,m来表示m种不同的颜色。
x[i]表示顶点i所着的颜色来,则问题的解向量可以表示为n元组x[1:n]。
问题的解空间可表示一棵高度为n+1的完全m叉树。
解空间树的第i层中每一结点都有m个儿子,每个儿子相应于x[i]的m个可能的着色之一,第n+1层结点均为叶结点。
在回溯算法Backtrack中,当i>n时,表示算法已搜索至一个叶结点,得到一个新的m着色方案,因此当前已找到的可m着色方案数sum增1。
当i≤n时,当前扩展结点Z是解空间树中的一个内部结点。
该结点有x[i]=1,2,…,m。
对当前扩展结点Z的每一个儿子结点,由函数Ok检查其可行性,并以深度优先的方式递归地对可行子树进行搜索,或剪去不可行子树。
五、实验结果
源程序:
#include<iostream>
using namespace std;
int color[100],sum;
bool ok(int k,int c[100][100])
{
for(int i=1;i<k;i++)
if(c[k][i]==1&&color[i]==color[k])
return false;
return true;
}
void backtrack(int k,int n,int m,int c[100][100]) {
if(k>n){
for(int i=1;i<=n;i++)
cout<<color[i]<<" ";
cout<<endl;
sum++;
}
else
for(int i=1;i<=m;i++){
color[k]=i;
if(ok(k,c)) backtrack(k+1,n,m,c);
color[k]=0;
}
}
int main()
{
int i,j,n,m;
int c[100][100];
cout<<"输入顶点数n和着色数m:\n";
cin>>n;
cin>>m;
cout<<"输入无向图的邻接矩阵:\n";
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>c[i][j];
cout<<"着色所有可能的解:\n";
backtrack(1,n,m,c);
cout<<"着色可能解的总数为:"<<sum<<endl;
system("pause");
return 0;
}。