最大团问题问题提出是,给定一个无向图
,如下图所示,选择顶点集合V的一个子集,这个子集中任意两个顶点之间的边都属于边集E,且这个子集包含顶点的个数是顶点集合V所有同类子集中包含顶点个数最多的。
采用回溯法求解该最大团问题,并回答以下问题:
1)分析该问题解空间和解空间结构。
1、定义最大团问题的解空间
最大团问题的解可以表示为一个n元组{x1,x2,…,xn},xi(1<=i<=n)的取值为1或0,表示顶点i属于或不属于最大团。
2、建立最大团问题的解空间结构
最大团问题的解空间结构可以表示为一棵完全二叉树。解空间树中的每个结点都有左右两个分支,左分支用1标识,表示第i个顶点属于最大团;右分支用0标识,表示第i个顶点不属于最大团。这棵解空间树有2n个叶结点,解空间树从树的根结点到叶结点的路径定义了最大团问题的一个解。
2)写出算法实现代码并截屏程序的运行结果。
package twelve;
public class MaxClique {
static int[] x;//当前解,往左为1,右为0
static int n = 6;//图G的顶点数
static int cn;//当前顶点数(团中)
static int bestn;//当前最大顶点数
static int[] bestx;//当前最优解
static int[][] a = {{0,0,0,0,0,0,0},
{0,0,1,0,1,1,1},
{0,1,0,1,1,1,0},
{0,0,1,0,1,0,0},
{0,1,1,1,0,1,0},
{0,1,1,0,1,0,1},
{0,1,0,0,0,1,0}};//图G的邻接矩阵
public static void main(String[] args) {
maxClique();
backtrack(1);
System.out.println("x:");
show(x);
System.out.println("bestx:");
show(bestx);
System.out.println("bestn="+bestn);
}
public static void show(int[] a)
{
for(int i:a)
{
System.out.print(i+" ");
}
System.out.println();
}
public static void show(int[][] a)
{
for(int i = 1;i<a.length;i++)
{
for(int j = 1;j<a[i].length;j++)
{
System.out.print(a[i][j]+" ");
}
System.out.println();
}
System.out.println();
}
public static int maxClique()//初始化
{
x = new int[n+1];
cn = 0;
bestn = 0;
bestx = new int[n+1];
backtrack(1);
return bestn;
}
public static void backtrack(int i)
{
if(i > n)
{
//到达叶结点
for(int j = 1;j <= n;j++) bestx[j] = x[j];
bestn = cn;
return;
}
int ok = 1;//标签变量,1入团,0不入
for(int j = 1;j < i;j++)//检查顶点i与当前团的连接
if(x[j] == 1 && a[i][j] == 0)
{
ok = 0;
break;
}
if(ok == 1)
{
//进入左子树
x[i] = 1;
cn++;
backtrack(i+1);//找下一层
cn--;
}
if(cn+n-i > bestn)
{
//进入右子树
x[i] = 0;//标记为向右
backtrack(i+1);
}
}
}
运行结果截图:
3)对算法做复杂性分析。
时间复杂度为O(n2n)。
图的m着色问题提出是,给定图
和m种颜色,如下图所示。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。问是否有一种着色法使G中每条边的2个顶点着不同颜色。采用回溯法判断该图是否是
可着色的,并且确定该图的色数。
1)分析该问题解空间及解空间结构。
1、定义图的m着色问题的解空间
图的m卓藕色问题的解可以表示为一个n元组{x1,x2,…,xn},整数1,2,…,m用来表示m种不同颜色,xi(1<=i<=n)的取值表示顶点i所用的颜色。
2、建立图的m着色问题的解空间结构
图的m着色问题的解空间结构可表示为一棵完全m叉树。解空间树的每层中的每个结点都有m个子结点,每个子结点对应于xi的m个可能的着色之一。解空间树有mn个叶结点。这棵解空间树从树的根结点到叶结点的路径定义了图的一个m可着色方案。
2)写出算法实现代码并截屏程序的运行结果。
package twelve;
public class Coloring {
static int n = 6;//图的顶点数
static int m;//可用颜色数
static int[][] a = {{0,0,0,0,0,0,0},
{0,0,1,0,0,1,1},
{0,1,0,1,1,1,0},
{0,0,1,0,1,0,0},
{0,0,1,1,0,1,0},
{0,1,1,0,1,0,1},
{0,1,0,0,0,1,0}};//图的邻接矩阵(有边为1,无边为0)
static int[] x;//当前解(选择何种颜色)
static long sum;//当前已找到的m可着色方案数
public static void main(String[] args) {
mColoring(3);
System.out.println("sum="+sum);
}
public static long mColoring(int mm)
{
m = mm;
sum = 0;
x = new int[n+1];
backtrack(1);
return sum;
}
private static void backtrack(int t)
{
if(t>n)
{
sum++;
for(int i = 1;i<=n;i++)
System.out.print(x[i]+" ");
System.out.println();
}
else//可扩展结点
for(int i = 1;i<=m;i++)
{
x[t] = i;//加色
if(ok(t)) backtrack(t+1);//可达结点
x[t] = 0;//去色
}
}
private static boolean ok(int k)
{
for(int j = 1;j<=n;j++)
{
if(a[k][j] == 1/*有边相连为1*/ && x[j]==x[k]) return false;//颜色与相邻点相同,则不可着色
}
return true;
}
}
运行结果截图:
m=5
m=4
m=3
3)对算法做复杂性分析。
图的m可着色问题的解空间树中,内结点的个数是。对于每个内结点,在最坏情况下,用约束函数检查每个儿子结点的颜色可用性需要花费的时间是O(mn),因此其时间复杂度为O(nmn)。
来自《算法基础与实验》