图的m着色问题回溯法

合集下载

《算法设计与分析》考试题目及答案(DOC)

《算法设计与分析》考试题目及答案(DOC)

《算法设计与分析》考试题目及答案(DOC)D. 预排序与递归调用7. 回溯法在问题的解空间树中,按(D)策略,从根结点出发搜索解空间树。

A.广度优先B. 活结点优先 C.扩展结点优先 D. 深度优先8. 分支限界法在问题的解空间树中,按(A)策略,从根结点出发搜索解空间树。

A.广度优先B. 活结点优先 C.扩展结点优先 D. 深度优先9. 程序块(A)是回溯法中遍历排列树的算法框架程序。

A.B.C.D. void backtrack (int t){if (t>n) output(x);elsefor (int i=t;i<=n;i++) {swap(x[t], x[i]);if (legal(t)) backtrack(t+1); swap(x[t], x[i]);}}void backtrack (int t){if (t>n) output(x);elsefor (int i=0;i<=1;i++) {x[t]=i;if (legal(t)) backtrack(t+1); }}10. 回溯法的效率不依赖于以下哪一个因素?(C )A.产生x[k]的时间;B.满足显约束的x[k]值的个数;C.问题的解空间的形式;D.计算上界函数bound的时间;E.满足约束函数和上界函数约束的所有x[k]的个数。

F.计算约束函数constraint的时间;11. 常见的两种分支限界法为(D)A. 广度优先分支限界法与深度优先分支限界法;B. 队列式(FIFO)分支限界法与堆栈式分支限界法;C. 排列树法与子集树法;D. 队列式(FIFO)分支限界法与优先队列式分支限界法;12. k带图灵机的空间复杂性S(n)是指(B)A.k带图灵机处理所有长度为n的输入时,在某条带上所使用过的最大方格数。

B.k带图灵机处理所有长度为n的输入时,在k条带上所使用过的方格数的总和。

C.k带图灵机处理所有长度为n的输入时,在k条带上所使用过的平均方格数。

回溯法实验(图的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++实现(含详细注释)

图的着色问题--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,2,3,...16 这16个数字填写在4 x 4的方格中。 16 ? ? 13 ? ? 11 ? 9??* ? 15 ? 1
表中有些数字已经显露出来,还有些用?和*代替。 请你计算出? 和 * 所代表的数字。并把 * 所代表的数字作为本题答 案提交。
素数环问题
素数环是一个计算机程序问题,指的是将从1到n这n个整数围成一 个圆环,若其中任意2个相邻的数字相加,结果均为素数,那么这个环 就成为素数环。现在要求输入一个n,求n个数围成一圈有多少种素数 环,规定第一个数字是1。 143256 165234
例如当n=5,m=4时,面值为1,3,11,15,32的5种邮票可以贴 出邮资的最大连续区间是1到70。
➢ 通用的解题法 ➢ 核心在于构造解空间树:
➢ 子集树 ➢ 排列树 ➢ 回溯法是优化的暴力搜索: ➢ 不满足限制条件; ➢ 当前解与最优解进行预计算; ➢ 学习回溯法:心中有树
回溯法
总结
➢ 动态规划适合两个连续步骤之间有联系的问题; ➢ 回溯法几乎适用于所有的问题,但问题之间最好有明确的层次。
总结
➢ 构造心中的解空间树是关键; ➢ 回溯法与函数的局部变量; ➢ 访问解空间树的优化处理;
迷宫问题中的回溯法
➢ 四邻域 ➢ 八邻域
图论问题
无向图: ➢ 连通 ➢ 不连通
有向图: ➢ 弱连通 ➢ 单向连通 ➢ 强连通
最大团问题
连通子图(分支)
最大团问题
给定无向图G=(V,E),如果UV,且对任意的u,vU, 都有(u,v)E,则称U是G的完全子图。G的完全子图U是G 的一个团当且仅当U不包含在G的更大的完全子图中。G中 的最大团是指G中所含顶点数最多的团。
yes no yes
➢ 通用的解题法 ➢ 核心在于构造解空间树:

图的着色问题

图的着色问题

问题来源
图的着色
通常所说的着色问题是指下述两类问题: 通常所说的着色问题是指下述两类问题: 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。 由此可见, 由此可见,求色数其需要求极大独立集以 及一切若干极大独立集的和含所有顶点的子 对于大图, 集,对于大图,因为图计算量过大而成为实 际上难以凑效的算法,所以不是一个好算法, 际上难以凑效的算法,所以不是一个好算法, 一般我们采用贪心法等近似算法来求解 。

深度优先搜索与回溯算法

深度优先搜索与回溯算法

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、二分搜索算法是利用(分治策略)实现的算法。

9. 实现循环赛日程表利用的算法是(分治策略)27、Strassen矩阵乘法是利用(分治策略)实现的算法。

34.实现合并排序利用的算法是(分治策略)。

实现大整数的乘法是利用的算法(分治策略)。

17.实现棋盘覆盖算法利用的算法是(分治法)。

29、使用分治法求解不需要满足的条件是(子问题必须是一样的)。

不可以使用分治法求解的是(0/1背包问题)。

动态规划下列不是动态规划算法基本步骤的是(构造最优解)下列是动态规划算法基本要素的是(子问题重叠性质)。

下列算法中通常以自底向上的方式求解最优解的是(动态规划法)备忘录方法是那种算法的变形。

(动态规划法)最长公共子序列算法利用的算法是(动态规划法)。

矩阵连乘问题的算法可由(动态规划算法B)设计实现。

实现最大子段和利用的算法是(动态规划法)。

贪心算法能解决的问题:单源最短路径问题,最小花费生成树问题,背包问题,活动安排问题,不能解决的问题:N皇后问题,0/1背包问题是贪心算法的基本要素的是(贪心选择性质和最优子结构性质)。

回溯法回溯法解旅行售货员问题时的解空间树是(排列树)。

剪枝函数是回溯法中为避免无效搜索采取的策略回溯法的效率不依赖于下列哪些因素(确定解空间的时间)分支限界法最大效益优先是(分支界限法)的一搜索方式。

分支限界法解最大团问题时,活结点表的组织形式是(最大堆)。

分支限界法解旅行售货员问题时,活结点表的组织形式是(最小堆)优先队列式分支限界法选取扩展结点的原则是(结点的优先级)在对问题的解空间树进行搜索的方法中,一个活结点最多有一次机会成为活结点的是( 分支限界法).从活结点表中选择下一个扩展结点的不同方式将导致不同的分支限界法,以下除( 栈式分支限界法)之外都是最常见的方式.(1)队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。

(2)优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。

回溯算法---例题7.图的m着色问题

回溯算法---例题7.图的m着⾊问题⼀.问题描述给定⽆向连通图G和m种不同的颜⾊.⽤这些颜⾊为图G的各项点着⾊,每个项点画⼀种颜⾊.是否有⼀种着⾊法,使G中每条边的2个顶点有着不同颜⾊?⼆.解题思路图的m⾊判定问题:给定⽆向连通图G和m种颜⾊。

⽤这些颜⾊为图G的各顶点着⾊. 问是否存在着⾊⽅法, 使得G中任2邻接点有不同颜⾊。

图的m⾊优化问题:给定⽆向连通图G,为图G的各顶点着⾊, 使图中任2邻接点着不同颜⾊,问最少需要⼏种颜⾊。

所需的最少颜⾊的数⽬m称为该图的⾊数若图G是可平⾯图,则它的⾊数不超过4⾊(4⾊定理).4⾊定理的应⽤:在⼀个平⾯或球⾯上的任何地图能够只⽤4种颜⾊来着⾊使得相邻的国家在地图上着有不同颜⾊例如:[这⾥有⼀个适⽤于任意图着⾊的Welch Powell法,感兴趣的同学可以看看.](#Welch Powell)回到该问题,我们可以很清晰地看出问题的解空间树是⼀棵排列树,因为我们确定n个元素满⾜某种性质的排列,这个性质就是⼀条边的两个点颜⾊不相同.⽽不是说找到n个元素的⼀个⼦集,这是要做的第⼀步.具体的算法实现上:设图G=(V, E), |V|=n, 颜⾊数= m, ⽤邻接矩阵a表⽰G, ⽤整数1, 2…m来表⽰m种不同的颜⾊。

顶点i所着的颜⾊⽤x[i]表⽰。

问题的解向量可以表⽰为n元组x={ x[1],...,x[n] }. x[i]Î{1,2,...,m},解空间树为排序树,是⼀棵n+1层的完全m叉树.在解空间树中做深度优先搜索, 约束条件: x[i] ≠ x[j], 如果a[j].[i] = 1.代码如下:// 图的m着⾊问题#include<bits/stdc++.h>using namespace std;class Color{friend int mColoring(int, int, int **);private:bool CanDraw(int k);void Backtrack(int i);int n, //图的顶点数m, //可⽤颜⾊数**a, //图的邻接矩阵*x; //当前解long sum; //当前已经找到的可m着⾊⽅案数};bool Color::CanDraw(int i) //检查第i层填写的颜⾊x[i]是否可⽤{for(int j=1; j<i; j++){if(a[i][j]==1 && x[j]==x[i])return false;}return true;}void Color::Backtrack(int i){if(i > n){sum++;cout<<"第"<<sum<<"个解:";for(int i=1; i<=n; i++)cout<<x[i]<<" ";cout<<endl;return;}for(int k=1; k<=m; k++) //依次从m种颜⾊中选择,由于每⼀个分⽀的处理⽅法⼀样,所以直接⽤⼀个循环,⽽不需要分别写{x[i] = k;if(CanDraw(i)){cout<<"颜⾊"<<k<<"可⾏,深⼊⼀层,将到达"<<i+1<<"层"<<endl;Backtrack(i+1);cout<<"回溯⼀层到达第"<<i<<"层"<<endl;}else{if(k==m) cout<<"当前层所有颜⾊选完,没有可⾏颜⾊,故将回溯⼀层到达第"<<i-1<<"层"<<endl;else cout<<"颜⾊"<<k<<"不可⾏,继续选择颜⾊"<<k+1<<endl;}x[i] = 0;}}int 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;X.Backtrack(1);delete[] p;return X.sum;}int main(){cout<<"请输⼊顶点个数和颜⾊种数:";int n, m;while(cin>>n>>m && n && m){cout<<"请输⼊邻接矩阵"<<endl;int **a = new int*[n+1];for(int i=0; i<=n; i++) a[i] = new int[n+1];for(int i=1; i<=n; i++)for(int j=1; j<=n; j++)cin>>a[i][j];int ans = mColoring(n, m, a);cout<<"图的"<<m<<"着⾊⽅案共有"<<ans<<"种"<<endl;for(int i=0; i<=n; i++) delete[] a[i];delete[] a;cout<<"请输⼊顶点个数和颜⾊种数:";}system("pause");return 0;}运⾏结果:由此可以结合排列树看⼀看,⼗分清晰明了.参考毕⽅明⽼师《算法设计与分析》课件.欢迎⼤家访问个⼈博客⽹站---,和我⼀起加油吧!针对任意图着⾊问题,Welch Powell⽅法:将G的结点按照度数递减的次序排列⽤第⼀种颜⾊对第⼀个结点着⾊,并按照结点排列的次序对与前⾯着⾊点不邻接的每⼀点着以相同颜⾊⽤第⼆种颜⾊对尚未着⾊的点重复步骤2,⽤第三种颜⾊继续这种作法,直到所有点着⾊完为⽌例如:。

图着色问题——精选推荐

图着⾊问题⼀、图着⾊问题(1)图的m可着⾊判定问题给定⽆向连通图G和m种不同的颜⾊。

⽤这些颜⾊为图G的各顶点着⾊,每个顶点着⼀种颜⾊。

是否有⼀种着⾊法使G中每条边的2个顶点着不同颜⾊。

(2)图的m可着⾊优化问题若⼀个图最少需要m种颜⾊才能使图中每条边连接的2个顶点着不同颜⾊,则称这个数m为该图的⾊数。

⼆、m可着⾊判定问题的解法【算法】(1)通过回溯的⽅法,不断的为每⼀个节点着⾊,在前⾯cur-1个节点都合法的着⾊之后,开始对第cur-1个节点进⾏着⾊,(2)这时候枚举可⽤的m个颜⾊,通过和第cur-1个节点相邻的节点的颜⾊,来判断这个颜⾊是否合法(3)如果找到那么⼀种颜⾊使得第cur-1个节点能够着⾊,那么说明m种颜⾊的⽅案在当前是可⾏的。

(4)cur每次迭代加1,如果cur增加到N并通过了检测,说明m种颜⾊是可满⾜的。

(5)注意,这⾥只是要求判断m种颜⾊是否可满⾜,所以找到任何⼀种⽅案就可以了。

【代码实现】#include<iostream>#include<cstring>using namespace std;const int maxn = 105;int G[maxn][maxn];int color[maxn];bool ans;int n,m,k;void init(){ans = 0;memset(G, 0 , sizeof G);memset(color, 0 , sizeof color);}void dfs(int cur){if(cur > n) {ans = 1;return;}for(int i=1; i<=m; i++){ //对cur结点尝试使⽤每⼀种颜⾊进⾏涂⾊bool flag = 1;//cur之前的结点必被涂⾊for(int j=1; j<cur; j++){if(G[j][cur] == 1 && color[j] == i){flag = 0;//只要有⼀个冲突都不⾏break;}}//如果可以涂上i颜⾊,则考虑下⼀个结点的情况if(flag){color[cur] = i;dfs(cur + 1);}//如果到这⼀步第cur个结点⽆法着⾊,则返回探寻其他⽅案else color[cur] = 0;//回溯 ;}}int main(){while(cin>>n>>k>>m){init();for(int i=1; i<=k; i++){int x,y;cin>>x>>y;G[x][y] = G[y][x] = 1;}dfs(1);cout<<ans<<endl;}return0;}三、m可着⾊拓展【问题】在上述基础上,求出m种颜⾊能够给图G涂⾊的总总⽅案数量【算法】由于这个时候要求总⽅案数量,所以在找到⼀种可⾏⽅案后,总是进⾏回溯再搜索其他的解决⽅案,与上⾯不同,上⾯是只需要找出⼀种⽅案即可,所以如果找到了就不需要再回溯了,所以在这⾥只需要把回溯语句的位置写到dfs语句的后⾯即可。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Coloring(intnewn,intnewm)//定义构造函数,为对象的各属性赋初值
{
n =newn;
m =newm;
sum = 0;
x = newint[n+5];
a = newboolean[n+5][m+5];
}
public longmColoring(intmm)//显示每次搜索后总搜索结果
***********************************/
importjava.io.*;//引入java.io包中的所有类
/*******************************************
*函数名:Class1
*
*传入值:顶点数n,颜色数m
*
*输出值:当前解x,着色方案sum
3.图的m着色的回朔算法的程序:
/*********************************
*程序名:图的m着色法
*
*版本:V J++6.0*
*开发日期:2005.10.25
*
*简要说明:此程序实现给定无向量图顶点和m种不同的颜色。用这些颜色为图的各顶点着色,每个顶点着一种颜色,
*
*并使图中每条边的两个顶点着色不同。求有多少个图色的方法?
在算法backtrack中,当i>n时,算法搜索至叶结点,得到新的m着色方案,当前找到的m着色方案数sum增1。
当I<n时,当前扩展结点Z的每一个解空间中内部结点.该结点有x[i]=1,2,…,m共m个儿子结点.对当前扩展结点Z的每一儿子结点,有方法ok检查其可行性,并以深度优先的方式递归的对可行子树搜索,或减去不可行树.
*
*简要说明:定义主类和输入输出,并调用定义类Coloring
*******************************************/
public class Class1//定义主类,并调用定义类Coloring
{
public static void main( Stringargs[] )
t=0
扩展结点的每一个儿子所相应的颜色可用性需耗时O(mn).因此,回朔法总的时间耗费是
n-1
∑mi (mn)=mn(m^-1)/(m-1)=O(nm^)
t=0
{
m = mm;
sum=0;
backtrack(1);
return sum;
}
public void backtrack(intt)//对解空间树进行搜索
{
if ( t > n )//搜索解空间树至叶节点
{
sum++;
for (inti=1;i<= m;i++ )
{
System.out.print(x[i]+"->");
2.算法设计
一般连通图的可着色法问题并不仅限于平面图。给定图G=(V,E)和m种颜色,果这个图不是m可着色,给出否定回答,如果这个图是m的可着色的,找出所有不同的着色法。
下面根据回朔法的递归描述框架backtrack设计图的m着色算法。用图的邻接矩阵a表示无向量连通图G=(V,E)。若(i,j)属于图G=(V,E)的边集E,则a[i][j]=1,否则a[i][j]=0。整数1,2,…,m用来表示m种不同颜色。顶点i所有颜色用x[i]表示,数组x[1:n]是问题的解向量。问题的解空间可表示为一棵高度为n+1的完全m叉树。解空间树的第I(1<=i<=n)层中每一结点都有m个儿子,每个儿子相应于x[i]的m个可能的着色之一。第n+1层结点均为叶结点。
{
if ( a[k][j] && (x[j]==x[k]) )
{
return false;
}
else
{;}}源自return true;}
}
4.比对程序
5.算法效率
图的m可着色回朔法的计算时间上界可以通过解空间树中内结点个数估计.图的可着色问
n-1
题的解空间数中内结点个数是∑mi.对于每一个内结点,在最坏情况下,用方法ok检查当前
}
System.out.println();
}
else//搜索解空间树的内结点
{
for (inti=1;i<= m;i++ )
{
x[t]=i;//保存填充的颜色
if ( ok(t) )
{
backtrack(t+1);
}
}
}
}
privatebooleanok(intk )//检查颜色可用性
{
for (intj=1; j <= n; j++ )
BufferedReaderreader;
in = newInputStreamReader(System.in);
reader = newBufferedReader(in);
String s = "";
try
{
s =reader.readLine();
}
catch(IOExceptione)
{
System.out.println();
System.exit(0);
}
System.out.println("The End!");
}
}
/*******************************************
*函数名:Coloring
*
*传入值:当前解x,着色方案sum
*
*输出值:当前解x,着色方案sum
*
*简要说明:图的可着色方法的回朔算法
图的m着色问题
1.问题描述
给定无向量图G顶点和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G图中每条边的两个顶点着不同的颜色。这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的两个顶点着不同的颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色问题。
*******************************************/
class Coloring//定义类,表示图的m着色问题
{
intn,m;//图的顶点数,可用颜色数
boolean[][] a;//图的邻接矩阵
int[] x;//当前解
long sum;//当前可找到的m着色方案数
{
ColoringmyColor= new Coloring(3,3);//为Coloring类创建一个新对象
System.out.println( "sum=" +myColor.mColoring(3) );//输出着色方案最后结果
InputStreamReaderin;//使运行结果的显示暂停
相关文档
最新文档