【算法设计与分析】回溯法:最大团问题与图的m着色问题

最大团问题问题提出是,给定一个无向图在这里插入图片描述
,如下图所示,选择顶点集合V的一个子集,这个子集中任意两个顶点之间的边都属于边集E,且这个子集包含顶点的个数是顶点集合V所有同类子集中包含顶点个数最多的。
【算法设计与分析】回溯法:最大团问题与图的m着色问题_第1张图片
采用回溯法求解该最大团问题,并回答以下问题:
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);
		}
	}
}

运行结果截图:
【算法设计与分析】回溯法:最大团问题与图的m着色问题_第2张图片
3)对算法做复杂性分析。
时间复杂度为O(n2n)。

图的m着色问题提出是,给定图在这里插入图片描述
和m种颜色,如下图所示。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。问是否有一种着色法使G中每条边的2个顶点着不同颜色。采用回溯法判断该图是否是在这里插入图片描述
可着色的,并且确定该图的色数。
【算法设计与分析】回溯法:最大团问题与图的m着色问题_第3张图片
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=4
【算法设计与分析】回溯法:最大团问题与图的m着色问题_第5张图片
m=3
【算法设计与分析】回溯法:最大团问题与图的m着色问题_第6张图片
3)对算法做复杂性分析。
图的m可着色问题的解空间树中,内结点的个数是。对于每个内结点,在最坏情况下,用约束函数检查每个儿子结点的颜色可用性需要花费的时间是O(mn),因此其时间复杂度为O(nmn)。
来自《算法基础与实验》

你可能感兴趣的:(算法)