菜鸟学习回溯法

笔记 专栏收录该内容
7 篇文章 0 订阅

回溯法

直接上题
设下图G=(V,E)是一连通无向图,有3种颜色,用这些颜色为G的各顶点着色,每个顶点着一种颜色,且相邻顶点颜色不同。试用回溯法设计一个算法,找出所有可能满足上述条件的着色法,如果这个图不能用3种颜色着色满足相邻顶点颜色互异的要求就给出否定的回答。

在这里插入图片描述
这里因为是作业要求 所以用C语言实现
采用的是邻接矩阵 也可以采用邻接链表 不过这里节点较少就采用了邻接矩阵
关键是如何进行回溯
由题可知
每一个节点由三种着色方式 所以 每一个节点要进行三次循环来遍历颜色 并且要确定每一个与其相邻的节点的颜色是否已经重复 重复了的要直接结束
代码如下

#include<stdlib.h>
#include<stdio.h>
#define MAX 20

// 回溯法解决着色问题
// 构建邻接矩阵 节点较少
static int n;
static int Graph[MAX][MAX] = { 0 };
static enum STATE { empty, first, second, third };
enum STATE color[MAX];
static void PrintColor()
{
	for (int i = 0; i < n; i++)
		printf(" %d\t", color[i]);
	printf(" \n");
}

static int hasColor(int u) // 判断是否存在相同的颜色
{
	//上色之前先判断
	for (int i = 0; i < n; i++)
	{
		if (i == u) // 等于自己的时候跳过
			continue;
		if (Graph[u][i]) // 找到相邻的元素
		{
			if (color[u] == color[i]) // 寻找相邻元素中的是否存在一个点和当前颜色相同
			{
				return 1;
			}
		}
	}
	return 0;
}

static int flashback(int u)
{
	if (u == n)  // 成功完全着色 
	{
		PrintColor();
		return;
	}
	else {
		for (enum STATE state = first; state <= third; state++)
		{
			color[u] = state;  // 给自己上色
			if (!hasColor(u))  // 不存在颜色 这里的顺序一定要注意
				flashback(u + 1);// 遍历下一个节点
			color[u] = empty; // 这里设置为empty 方便下一次使用
		}
	}
}

int main()
{
	//确定有多少节点
	int  u, k, t;
	scanf(" %d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf(" %d %d", &u, &k); // u为节点 k为度数 由于是从0开始 所以不用-1
		for (int j = 0; j < k; j++)
		{
			scanf(" %d", &t);
			Graph[u][t] = 1;
		}
		color[i] = empty; // 初始化状态
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			printf(" %d ", Graph[i][j]);
		printf(" \n");
	}
	printf(" 调用着色方法\n");
	flashback(0);
	return 0;
}

运行结果
在这里插入图片描述

flashback()函数中

if (!hasColor(u))  // 给自己上色
		flashback(u + 1);// 遍历下一个节点
color[u] = empty; // 这里设置为empty 方便下一次使用

这里顺序不能反过来 我之前写的是

if ( hasColor( u))
	color[u] = empty;
flashback( u+1);

结果死活不对 单步调试发现
如果这样写 就会出现如果当前元素uthird的时候刚好符合条件
就会进行下一个节点调用 现在假设下一个节点返回 就会出现color[u]无法被初始化就会保留结果 从而影响回溯的结果
在这里插入图片描述
如果有说错的地方 还请大佬提出来(轻喷) 谢谢各位观看

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值