算法设计:实验四回溯法

news2024/12/25 9:22:07

【实验目的】

应用回溯法求解图的着色问题

【实验要求】

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

 

【算法思想及处理过程】

回溯法是一种通过递归尝试所有可能的解决方案以找到满足问题条件的所有解的算法。

回溯法的基本思想可以总结如下:

选择候选:尝试在当前位置选择一个候选解。

合法性检查:检查当前选择是否满足问题的约束条件。

递归前进:如果选择合法,继续尝试下一个位置的候选解。

回溯:如果在某一步无法继续或所有候选均不合法,则撤销之前的选择(即回溯),尝试其他候选解。

具体步骤如下:

初始化:定义一个表示当前状态的数据结构,初始化为初始状态。

递归函数:设计一个递归函数,尝试在当前状态的基础上构造解。

边界条件:定义递归终止条件(例如已经构造出一个完整解)。

候选选择和合法性检查:在递归函数中,尝试所有可能的候选解,并检查其合法性。

回溯:如果当前选择不合法或递归未找到解,则撤销当前选择,继续尝试其他候选解。

在本题中:

输入和初始化:

输入图的顶点数量 num_vertices。

输入图的邻接矩阵 graph。

初始化颜色数组 color_assignment,初始值为 -1,表示未着色。

递归函数 colorGraphUtil:

递归地尝试为每个顶点着色。

如果所有顶点都已着色,打印当前着色方案,并增加解的计数。

合法性检查 isSafe:

检查当前顶点是否可以被指定颜色着色,即检查与当前顶点相邻的顶点是否有相同颜色。

回溯处理:

对于每个顶点,尝试三种颜色。

如果某种颜色可以合法地着色当前顶点,则递归处理下一个顶点。

如果递归成功(找到一个解),则继续。

否则,撤销当前顶点的着色(回溯),尝试其他颜色。

输出结果:

在递归结束后,打印所有找到的着色方案和总数。

在colorGraphUtil函数中

首先判断当前递归是否已完成所有顶点的着色。如果所有顶点都已着色,打印有效的着色方案并增加方案计数,然后结束递归。如果不是,则继续尝试每种颜色。对每个颜色进行尝试。如果当前颜色合法,将颜色赋给当前顶点,并递归处理下一个顶点。递归返回后,撤销当前顶点的颜色赋值(回溯),尝试下一种颜色。如果所有颜色均不合法,撤销当前选择并返回上一级递归。

在isSafe函数中:

使用 for 循环遍历图中所有顶点,范围是 0 到 num_vertices - 1。

对于每个顶点 i,首先检查 graph[vertex][i],它表示顶点 vertex 和顶点 i 之间是否存在边(即是否相邻)。

如果 graph[vertex][i] 为 1(或 true),表示顶点 vertex 和顶点 i 相邻。

接着检查 color_assignment[i] == c,即顶点 i 是否已经被着色为颜色 c。

如果相邻顶点 i 已经被着色为颜色 c,则返回 false,表示当前顶点 vertex 不能被着色为颜色 c,因为这会导致相邻顶点颜色相同。

如果循环结束后没有发现任何相邻顶点与颜色 c 冲突,返回 true,表示当前顶点 vertex 可以安全地着色为颜色 c。

【程序代码】

#include <stdio.h>
#include <stdbool.h>

#define MAX_VERTICES 100

int graph[MAX_VERTICES][MAX_VERTICES]; // 邻接矩阵表示图
int num_vertices; // 图中顶点的数量
int num_colors; // 可用的颜色数量
int color_assignment[MAX_VERTICES]; // 存储顶点的颜色编号,-1表示未着色
int solution_count = 0; // 记录有效的着色方案数量

// 检查给定顶点是否可以着色为指定颜色
bool isSafe(int vertex, int c) {
    for (int i = 0; i < num_vertices; i++) {
        if (graph[vertex][i] && color_assignment[i] == c) {
            return false; // 与相邻顶点颜色相同,不安全
        }
    }
    return true;
}

// 回溯函数,尝试为顶点进行着色
void colorGraphUtil(int vertex) {
    if (vertex == num_vertices) {
        // 所有顶点都已着色完成,打印结果
        printf("找到一个有效的着色方案:\n");
        for (int i = 0; i < num_vertices; i++) {
            printf("顶点 %d: %d\n", i, color_assignment[i] + 1);
        }
        printf("\n");
        solution_count++; // 记录找到一个有效方案
        return;
    }

    // 尝试为当前顶点着色
    for (int c = 0; c < num_colors; c++) { // 遍历每种颜色
        if (isSafe(vertex, c)) {
            color_assignment[vertex] = c; // 将颜色赋给顶点 
            colorGraphUtil(vertex + 1); // 递归处理下一个顶点 
            color_assignment[vertex] = -1; // 回溯,尝试下一种颜色 
        }
    }
}

// 对图进行顶点着色
void colorGraph() {
    // 从第一个顶点开始进行着色
    colorGraphUtil(0);

    // 输出总共找到的有效着色方案数量
    printf("总共找到 %d 种有效的着色方案。\n", solution_count);
}

int main() {
    // 读取图的顶点数量和邻接矩阵
    printf("请输入图中顶点的数量:");
    scanf("%d", &num_vertices);

    printf("请输入可用的颜色数量:");
    scanf("%d", &num_colors);

    printf("请输入图的邻接矩阵(%d * %d):\n", num_vertices, num_vertices);
    for (int i = 0; i < num_vertices; i++) {
        for (int j = 0; j < num_vertices; j++) {
            scanf("%d", &graph[i][j]);
        }
    }

    // 初始化颜色赋值数组
    for (int i = 0; i < num_vertices; i++) {
        color_assignment[i] = -1; // 初始未着色
    }

    // 调用顶点着色函数
    colorGraph();

    return 0;
}

【运行结果】

【算法分析】

isSafe函数的时间复杂度为O(V),其中是顶点数量 um_vertices。这是因为它需要检查与当前顶点相邻的所有顶点。

colorGraphUtil 函数是递归调用的核心部分,每个顶点尝试 num_colors种颜色,每次尝试都调用 isSafe 检查当前颜色是否可行。

在最坏情况下,递归函数 colorGraphUtil的时间复杂度可以表示为T(V)=num_colors^V×V

每个顶点尝试num_colors种颜色:num_colors^V。

每次尝试颜色时,调用 isSafe 函数需要 (O(V)) 的时间。

所以,最坏情况下,总的时间复杂度为 (O(num_colors^V times V)),其中 (V) 是顶点的数量,num_colors是颜色的数量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cookie、Session、Token、JWT的区别

先总结 其实比较的话就只是Session、Token、JWT的区别&#xff0c;Session是基于Cookie的 这里暂时只比较Session和JWT的区别 存放位置不同 Session基于Cookie存储在服务端JWT存放在客户端&#xff0c;通常是在浏览器的Cookie或LocalStorage中。 JWT将 Token 和 Payload 加…

从学习到工作,2024年不可或缺的翻译助手精选

翻译工具利用先进的机器学习和自然语言处理技术&#xff0c;能够迅速将一种语言的文档转换为另一种语言&#xff0c;极大地促进了信息的无障碍流通。接下来&#xff0c;我们将介绍几款功能强大、操作简便的类似deepl翻译的工具&#xff0c;帮助你轻松应对各种翻译需求。 第一款…

容器网络(桥接、host、none)及跨主机网络(etcd、flannel、docker)

1.本地网络 1.bridge 所有容器连接到桥就可以使用外网&#xff0c;使用nat让容器可以访问外网&#xff0c;使用ip a s指令查看桥&#xff0c;所有容器连接到此桥&#xff0c;ip地址都是 172.17.0.0/16网段&#xff0c;桥是启动docker服务后出现&#xff0c;在centos使用bridge…

深度强化学习算法(五)(附带MATLAB程序)

深度强化学习&#xff08;Deep Reinforcement Learning, DRL&#xff09;结合了深度学习和强化学习的优点&#xff0c;能够处理具有高维状态和动作空间的复杂任务。它的核心思想是利用深度神经网络来逼近强化学习中的策略函数和价值函数&#xff0c;从而提高学习能力和决策效率…

数据结构(6.4_2)——最短路径问题_BFS算法

最短路径问题 BFS求无权图的单源最短路径 原代码 改造visit函数后

list的使用及其相关知识点

目录 ◉list的底层逻辑 ◉关于list的新增功能 ▲splice功能 ▲remove函数 ▲unique函数 ▲merge函数 ▲sort函数 ▣迭代器类型 ▲reverse函数 作为数据容器之一的list和其他容器的使用上有很多相似的地方&#xff0c;比如都有大致相同的构造函数&#xff0c;大致相同的头插尾插…

CUDA编程之CUDA Sample-5_Domain_Specific-volumeFiltering(光线追踪)

volumeFiltering演示了使用 3D 纹理和 3D 表面写入进行 3D 体积过滤。它从磁盘加载一个 3D 体积&#xff0c;并使用光线步进和 3D 纹理进行显示。 以下是该示例的主要内容和功能&#xff1a; 主要功能 3D 体积加载: 从磁盘加载 3D 体积数据&#xff0c;通常为医学成像数据或体…

图像处理中的腐蚀与膨胀算法详解

引言 在图像处理领域&#xff0c;形态学操作&#xff08;Morphological Operations&#xff09;是处理二值图像的重要工具。腐蚀&#xff08;Erosion&#xff09;和膨胀&#xff08;Dilation&#xff09;是形态学操作的两种基本形式&#xff0c;它们常用于消除噪声、分割图像、…

深入解析C#中的锁机制:`lock(this)`、`lock(privateObj)`与`lock(staticObj)`的区别

前言 在C#的多线程编程中&#xff0c;lock关键字是确保线程安全的重要工具。它通过锁定特定的对象&#xff0c;防止多个线程同时访问同一块代码&#xff0c;从而避免数据竞争和资源冲突。然而&#xff0c;选择适当的锁对象对于实现高效的线程同步至关重要。本文将深入探讨使用…

三种tcp并发服务器实现程序

都需先进行tcp连接 1、多进程并发 2、多线程并发 3、IO多路复用并发 &#xff08;1&#xff09;select &#xff08;2&#xff09;epoll

在VB.net中,LINQ在数据统计方面的应用,举例说明

标题 在VB.net中&#xff0c;LINQ在数据统计方面的应用&#xff0c;举例说明 正文 在VB.NET中&#xff0c;LINQ&#xff08;Language Integrated Query&#xff09;在数据统计方面有着广泛的应用。LINQ允许开发者以声明性的方式对数据集合进行复杂的查询和统计操作&#xff0c;…

笔记:Echarts 饼图 图例legend 自定义 换行

配置后效果&#xff1a;&#x1f447; 配置&#xff1a; let option {legend: [{data: ["融云", "融AI", "融安全", "融平台"],show: true,right: "3%",bottom: "20%",left: "center",icon: "re…

乾元通渠道商中标大理市自然灾害应急能力提升项目

近日&#xff0c;乾元通渠道商中标云南省大理市自然灾害应急能力提升项目&#xff0c;乾元通作为设备厂家&#xff0c;为项目提供通信指挥类装备&#xff08;多链路聚合设备&#xff09;QYT-X1。 青岛乾元通数码科技有限公司作为国家应急产业企业&#xff0c;深耕于数据调度算法…

医疗数字化转型数据中台架构方案(一)

为推进医疗数字化转型&#xff0c;我们提出构建数据中台架构方案&#xff1a;通过集成医院内外多个数据源&#xff0c;利用大数据、人工智能等技术对数据进行清洗、整合、标准化处理&#xff0c;形成高质量的数据资产&#xff1b;再基于云原生技术构建湖仓一体化大数据平台&…

【Python数据结构与算法】栈----合法出栈序列

题目&#xff1a;合法出栈序列 描述 给定一个由大小写字母和数字构成的&#xff0c;没有重复字符的长度不超过62的字符串x&#xff0c;现在要将该字符串的字符依次压入栈中&#xff0c;然后再全部弹出。 要求左边的字符一定比右边的字符先入栈&#xff0c;出栈顺序无要求。 …

守护夏日清凉:EasyCVR+AI视频智能管理方案为水上乐园安全保驾护航

随着夏季的来临&#xff0c;水上乐园成为了人们避暑消夏、亲子互动的理想去处。然而&#xff0c;随着游客量的激增&#xff0c;如何确保水上乐园的安全与秩序&#xff0c;提升游客体验&#xff0c;成为了管理者亟待解决的问题。为此&#xff0c;引入一套高效、智能的视频监控方…

Node.js原生开发脚手架工具(下)

前言 在现代软件开发中&#xff0c;脚手架工具成为提高开发效率和一致性的关键利器。使用Node.js原生开发自己的脚手架工具不仅能帮助自动化常见任务&#xff0c;还能根据具体需求进行高度定制。Node.js的异步非阻塞特性和丰富的模块系统使其成为构建这种工具的理想选择。本篇文…

使用 pnpm workspace 和 standalone 模式构建 Next.js 的 Docker 镜像

引言 本文将探讨如何利用 pnpm workspace 和 standalone 模式来构建 Next.js 应用程序的轻量级 Docker 镜像。这种方法通过仅在 node_modules 目录中包含必要的文件&#xff0c;显著减少了最终 Docker 镜像的大小。 Standalone 模式简介 通常情况下&#xff0c;所有在 depe…

MyPrint打印设计器(四)vue3 函数式调用组件

vue3 函数式调用组件 vue中&#xff0c;通常情况下调用一个组件需要以下步骤 导入组件在template引入组件&#xff0c;并且设置ref属性在js模块定义对应的ref属性通过ref对象调用对应的方法 如果这个组件在template是不必要的&#xff0c;那么可以通过函数式调用组件&#xff…

Windows 10/11 系统优化工具 Optimizer 16.7

Optimizer 功能特色 全语言支持&#xff08;提供19种语言&#xff09; 提高系统和网络性能 禁用不必要的窗口服务 禁用 Windows 遥测、小娜等 禁用 Office 遥测&#xff08;仅适用于 Office 2016&#xff09; 禁用 Windows 10 自动更新 一次快速下载有用的应用程序 卸载 UWP 应…