回溯算法第三篇(批处理作业调度、N皇后【基于排列树实现】、符号三角形问题)

news2024/11/15 13:44:43

目录

1. 批处理作业调度

2. N皇后【基于排列树实现】

3. 符号三角形问题


1. 批处理作业调度

题目描述:给定n个作业的集合 J = \left ( J_{1},J_{2} ,\cdots,J_{n}\right )。每个作业 J_{i} 都有两项任务分别在两台机器上完成。每个作业必须先由机器1处理,再由机器2处理。作业 J_{i} 需要机器j的处理时间为 jobs_{ji}\left ( i = 1,2,\cdots ,n; j=1,2 \right )。对于一个确定的作业调度,设 F_{ji} 是作业i在机器j上完成处理的时间,则所有作业在机器2上完成处理的时间和 f=\sum_{i=1}^{n}F_{2i} 称为该作业调度的完成时间和。

题目解析:

(1)批处理作业调度问题要求,对于给定的 n 个作业,制定最佳作业调度方案,使其完成时间和达到最小。

(2)批处理作业调度问题的一个常见例子是,在计算机系统中完成一批 n 个作业,每个作业都要先完成计算,然后将计算结果打印输出。计算任务由计算机的中央处理器是机器1,打印机是机器2。

(3)调度必须遵循两点:

  • 一个作业必须先由机器1处理,再由机器2处理,顺序不可颠倒;
  • 机器1处理n个作业的顺序必须和机器2处理n个作业的顺序相同(因为只有这样才能使作业调度的完成时间和最小)

(4)由于作业调度就是一个先后顺序的改变,所以解决这一类问题的决策树是排列树

具体举例如下:

如下图,给出了3个作业分别需要机器1和机器2的处理时间,试给出一种调度方案,使该作业调度的完成时间和最小。

3个作业可能的调度顺序有6种:1→2→3、1→3→2、2→1→3、2→3→1、3→1→2、3→2→1。经过计算,它们的完成时间和对应为:19、18、20、21、19、19,因此最佳调度方案为1→3→2,其完成时间和为18

1→3→2,其完成时间和为18为例子,

结果:3 + 7 + 8 = 18。 

注意:一个作业在第2台机器上开始的时间,是取决于上一个作业在机器2上完成的时间和自己本身在机器1上完成的时间的最大值。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test16 {
    /*
    定义一批作业
    (1)第一维度表示作业1,2,3
    (2)第二维度表示在机器1,还是机器2上运行的时间
     */
    int N = 3;//表示有三个作业需要调度
    int[][] jobs = {{2, 1}, {3, 1}, {2, 3}};
    boolean[] isJobsRun;
    int minTime = Integer.MAX_VALUE;//表示最小的运行时间
    int[] nowRun;//表示当前的机器的运行顺序
    int[] jobsRun;//表示最佳机器的运行顺序

    public void permute(int[][] jobs) {
        //1.初始化
        isJobsRun = new boolean[jobs.length];
        jobsRun = new int[jobs.length];
        nowRun = new int[jobs.length];
        Arrays.fill(nowRun, -1);
        //2.调用dfs(回溯的核心)
        dfs(0);
    }

    public void dfs(int t) {
        //当来到叶子节点后,就进行时间累加
        if (t == N) {
            int t1 = 0, t2 = 0, sum = 0;
            for (int x = 0; x < N; x++) {
                int i = nowRun[x];
        //一个作业在第2台机器上开始的时间,
        //是取决于上一个作业在机器2上完成的时间和自己本身在机器1上完成的时间的最大值
                t1 = t1 + jobs[i][0];
                t2 = Math.max(t1, t2) + jobs[i][1];
                //sum就是在累加没一个作业最后再机器2上完成的时间和
                sum += t2;
            }
            int tmpTime = minTime;//用来判断是否有最小值的改变
            minTime = Math.min(minTime, sum);
            //如果两者不相等,正面值有进行改变
            if (tmpTime != minTime) {
                //将本次的机器运转顺序记录下来
                for (int i = 0; i < N; i++) {
                    jobsRun[i] = nowRun[i] + 1;
                }
            }
        }
        //如果
        else {
            //每次都从第一个机器开始看起
            for (int i = 0; i < N; i++) {
                //证明这个作业没被选择
                if (isJobsRun[i] == false) {
                    //把这个作业标记为已选择
                    isJobsRun[i] = true;
                    //因为下标是从0开始,所以第1个作业就是 0 ;
                    nowRun[t] = i;
                    dfs(t + 1);
                    //恢复现场
                    isJobsRun[i] = false;
                    nowRun[t] = -1;
                }
            }
        }
    }

    public static void main(String[] args) {
        Test16 test16 = new Test16();
        test16.permute(test16.jobs);
        System.out.println(test16.minTime);
        for(int i = 0;i < test16.N;i++){
            System.out.println(test16.jobsRun[i] + " ");
        }
    }
}

2. N皇后【基于排列树实现】

题目描述:按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

解决方案如下:(建议配合全部代码一起看)

(1)算法思路(假设是 4 皇后)

    static int N;//皇后数量、行或者列的大小
    static int[] queenLocal;//表示皇后所在的位置,数组下标表示行,数组里面存储的值表示列

    queenLocal = new int[N];
    //让皇后们先按对角线排列
    for (int i = 0; i < queenLocal.length; i++) {
         queenLocal[i] = i;
    }

因为我们是基于排列树实现N皇后,根据N皇后的题目要求,每一行只能有一个皇后,则先让4个皇后按对角线先排好队,然后改变每一行皇后在每一列的不同位置可以得到的结果是否满足题意,若满足就是一种排列方式,进行output打印。

    //满足条件来到output方法,打印皇后们的所在位置
    public static void output() {
        for (int i = 0; i < N; i++) {
            System.out.println("第" + (i + 1) + "个皇后;" 
                    + "皇后在第" + i + "行的第" + queenLocal[i] + "列;");
        }
        System.out.println();
    }

(2)核心代码

   public static void dfs(int row) {
        //证明已经排列到最后一行了
        if (row == N) {
            output();
        } else {
            for (int i = row; i < N; i++) {
                //row表示当前序列的首位元素的下标
                //交换位置,最终达到排列顺序的改变,其实就是不断的改变居于首位的元素
                swap(queenLocal, row, i);
                if (legal(row)) {
                    //去往下一行,也可以理解为下一个元素,然后还是一样
                    //不断改变首位的元素,判断是否合法,合法就继续去往下一行
                    //或者说去判断下一个元素的合理性
                    dfs(row + 1);
                }
                //恢复现场:之前改变了首元素的位置,现在要还原,不然下次再改变首位置元素就会错乱
                swap(queenLocal, row, i);
            }
        }
    }

    //交换数据的代码
    public static void swap(int[] a, int i, int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }

全部代码:


//基于排列树实现N皇后
public class QueenTest2 {
    static int N;//皇后数量、行或者列的大小
    static int[] queenLocal;//表示皇后所在的位置,数组下标表示行,数组里面存储的值表示列

    //交换数据的代码
    public static void swap(int[] a, int i, int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }

    //进行位置是否合法的判断
    public static boolean legal(int row) {
        for (int i = 0; i < row; i++) {
            //第一个条件判断列是不是相同,是不是在不同行,已经选了同一列
            //有两种规律(1)行减行,列减列两值相等;(2)每条对角线行列相减都有各自的定值
            if (queenLocal[i] == queenLocal[row] ||
                    Math.abs(row - i) == Math.abs(queenLocal[row] - queenLocal[i])) {
                return false;
            }
        }
        return true;
    }

    //传入参数是第几行的意思
    //row表示从第几行开始算起;num表示几皇后
    public static void permute(int row, int num) {
        //1.初始化
        N = num;
        queenLocal = new int[N];
        //让皇后们先按对角线排列
        for (int i = 0; i < queenLocal.length; i++) {
            queenLocal[i] = i;
        }
        //2.开始回溯
        dfs(row);
    }

    //满足条件来到output方法,打印皇后们的所在位置
    public static void output() {
        for (int i = 0; i < N; i++) {
            System.out.println("第" + (i + 1) + "个皇后;"
                    + "皇后在第" + i + "行的第" + queenLocal[i] + "列;");
        }
        System.out.println();
    }

    public static void dfs(int row) {
        //证明已经排列到最后一行了
        if (row == N) {
            output();
        } else {
            for (int i = row; i < N; i++) {
                //row表示当前序列的首位元素的下标
                //交换位置,最终达到排列顺序的改变,其实就是不断的改变居于首位的元素
                swap(queenLocal, row, i);
                if (legal(row)) {
                    dfs(row + 1);
                }
                //恢复现场:之前改变了首元素的位置,现在要还原,不然下次再改变首位置元素就会错乱
                swap(queenLocal, row, i);
            }
        }
    }

    public static void main(String[] args) {
        //我这里用4皇后举例,只需要改变传入的num参数,就可以实现不同的皇后效果
        permute(0, 4);
    }
}

3. 符号三角形问题

题目描述:图是由14个“+”和14个“-”组成的符号三角形。两个同号下面都是“+”,两个异号下面都是“-”。在一般情况下,符号三角形的第一行有n个符号。符号三角问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。如下图所示:

解决方案如下:为了方便计算,先把上图的三角形变化成如下的三角形,在打印的时候,再将下列数组的打印成如上图所示。

上图所提到的内容,在代码 上会体现,注意理解!!!

根据题意:其实就是对第一行进行全排列,只要能来到第一行的最后一列,这就是其中一种情况,根据这种情况生成下面 N - 1 行的字符即可,最后记录“+”和“-”的数量,看是否满足条件即可!!!

public class TriangleTest {
    static int N = 7;//表示行和列都是7
    static char[][] triangle;//用来存放每次+和-的位置

    public static void permute() {
        //1.初始化
        triangle = new char[N][N];
        //2.回溯的核心
        dfs(0);
    }

    //判断是否满足"+"和"-"的数量是否满足题意
    public static boolean isSameTriangle() {
        int sumPlus = 0;//用来记录 + 的个数
        int sumSub = 0;//用来记录 - 的个数
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N - i; j++) {
                if (triangle[i][j] == '+')
                    sumPlus++;
                if (triangle[i][j] == '-')
                    sumSub++;
            }
        }
        //如果两者相等,返回true,证明满足题意
        if (sumPlus == sumSub)
            return true;
        return false;
    }

    //打印满足题意的三角形
    public static void printfTriangle() {
        for (int i = 0; i < N; i++) {
            //打印三角形前面的空白
            for (int x = 0; x < i; x++) {
                System.out.print(" ");//打印一个空格
            }
            //打印字符
            for (int j = 0; j < N - i; j++) {
                System.out.print(triangle[i][j] + " ");
            }
            //换行
            System.out.println();
        }
        System.out.println();
    }

    //排列到第一行的最后一列元素,开始进行构造三角形
    public static void output() {
        /*
        能进入这个方法,证明第一行已经排好了,
        所以从第二行第一列开始填充
         */
        for (int i = 1; i < N; i++) {
            //这个在上图有解释
            for (int j = 0; j < N - i; j++) {
                //两个同号下面都是“+”,两个异号下面都是“-”。
                triangle[i][j] = triangle[i - 1][j] == triangle[i - 1][j + 1]
                        ? '+' : '-';
            }
        }
        //判断是否满足"+"和"-"的数量都是14!
        //满足题意,就打印三角形
        if (isSameTriangle()) {
            printfTriangle();
        }
    }

    //这题的回溯核心代码
    public static void dfs(int col) {
        //能进入if,证明第一行的字符已经排列完了
        if (col == N) {
            output();
        } else {
            //第一行的col是 +
            triangle[0][col] = '+';
            //递归看第一行的下一列
            dfs(col + 1);

            //第一行的col是 -
            triangle[0][col] = '-';
            //递归看第一行的下一列
            dfs(col + 1);
        }
    }

    public static void main(String[] args) {
        permute();
    }
}

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

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

相关文章

大数据技术13:HBase分布式列式数据库

前言&#xff1a;2007年Powerset的工作人员&#xff0c;通过google的论文开发出了BigTable的java版本&#xff0c;即HBASE。2008年HBASE贡献给了Apache。HBase 需要依赖 JDK 环境。 一、Hadoop的局限 HBase 是一个构建在 Hadoop 文件系统之上的面向列的数据库管理系统。 要想…

实验03:OSPF配置网络实验

1.实验目的&#xff1a; 本实验的主要目的是了解OSPF协议的基本概念、OSPF网络的配置及验证&#xff0c;通过实验来掌握OSPF协议的工作原理、配置方法、路由表的生成过程等。 2.实验内容&#xff1a; 设计一个拓扑结构&#xff0c;并在网络设备上进行配置&#xff1b;配置OS…

2019年第八届数学建模国际赛小美赛C题预测通过拥堵路段所需的时间解题全过程文档及程序

2019年第八届数学建模国际赛小美赛 C题 预测通过拥堵路段所需的时间 原题再现&#xff1a; 在导航软件中&#xff0c;行程时间的估计往往是一个重要的功能。现有的导航软件往往通过出租车或安装了该软件的车辆获取实时GPS数据来确定当前的路况。在交通拥堵严重的情况下&#…

实验5:NAT配置

1.实验目的&#xff1a; 了解NAT的基本概念和功能 掌握NAT的配置方法和命令 观察和分析NAT的工作原理和流程 2.实验内容&#xff1a; 在路由器上配置静态NAT&#xff0c;实现内网主机通过公网IP地址访问外网服务器在路由器上配置动态NAT&#xff0c;实现内网主机通过公网I…

解决IDEA自动生成返回值带有final修饰的问题

解决自动生成返回值带有final修饰的问题。 快捷键是CtrlAltV&#xff0c;然后会出现final修饰。 怎么办呢&#xff1f; 点击右上角的“设置”图标&#xff0c;将下面的两个框取消勾选&#xff0c;然后回车即可。 以后就可以直接使用快捷键来自动生成返回值啦~ public class K…

UDP特性之组播(多播)

UDP特性之组播 1. 组播的特点2. 设置主播属性2.1 发送端2.2 接收端 3. 组播通信流程3.1 发送端3.2 接收端 4. 通信代码 原文链接 在公司测试广播和多播有一点问题。。。 1. 组播的特点 组播也可以称之为多播这也是UDP的特性之一。组播是主机间一对多的通讯模式&#xff0c;是…

深度学习面试题-05

scikit-learn是什么工具&#xff1f; scikit-learn学习 scikit-learn&#xff08;sklearn&#xff09;是一个用于机器学习的Python库&#xff0c;提供了许多用于数据挖掘和数据分析的工具。它建立在NumPy、SciPy和matplotlib等科学计算库的基础上&#xff0c;并提供了简单而有…

hive聚合函数之排序

1 全局排序&#xff08;Order By&#xff09; Order By&#xff1a;全局排序&#xff0c;只有一个Reduce。 (1&#xff09;.使用Order By子句排序 asc&#xff08;ascend&#xff09;&#xff1a;升序&#xff08;默认&#xff09; desc&#xff08;descend&#xff09;&#…

qt-C++笔记之std::tostring()、.toStdString()、.toLocal8Bit().constData()的使用场景

qt-C笔记之std::tostring()、.toStdString()、.toLocal8Bit().constData()的使用场景 参考博文&#xff1a;C笔记之system()用于在Qt中执行系统命令的习惯 code review! 注&#xff1a;之所以记录该笔记&#xff0c;是因为在Qt中自己经常使用C语言的int system( const char …

Python PDF转DOCX文档

第三方包&#xff1a;pdf2docx from pdf2docx import Converterdef convert_pdf_to_docx(pdf_path, docx_path):# 创建一个转换器对象converter Converter(pdf_path)# 将PDF转换为DOCXconverter.convert(docx_path, start0, endNone)# 关闭转换器converter.close()# 调用函数…

实验01:静态路由配置实验

1.实验目的&#xff1a; 本次实验的主要目的是了解静态路由的配置和实现原理&#xff0c;熟悉路由器的基本操作&#xff0c;掌握在网络中进行静态路由配置的方法和技巧。 2.实验内容&#xff1a; 搭建网络拓扑&#xff0c;包括三台路由器和两台PC。配置路由器的IP地址和路由…

WPF-UI HandyControl 简单介绍

文章目录 前言我的网易云专栏和Gitee仓库HandyControlHandyControl示例相关资源地址 我的运行环境快速开始和Material Design功能对比手风琴右键菜单自动补充滚动条轮播图消息通知步骤条托盘按钮 结尾 前言 最近我在研究如何使用WPF做一个比较完整的项目&#xff0c;然后我就先…

LeetCode Hot100 146.LRU缓存

题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&…

Python文本信息解析:从基础到高级实战‘[pp]]‘[

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python文本信息解析&#xff1a;从基础到高级实战&#xff0c;全文3600字&#xff0c;阅读大约10分钟。 文本处理是Python编程中一项不可或缺的技能&#xff0c;覆盖了广泛的…

软件测评中心 ▏科技项目验收测试流程和注意事项简析

科技项目验收测试是指对已开发完成的科技项目进行测试和评估&#xff0c;以确认其达到预期的功能和性能要求&#xff0c;保证项目的质量和可靠性。 一、科技项目验收测试的流程一般包括以下几个阶段&#xff1a;   1、需求分析和测试计划&#xff1a;在开始测试前&#xff0…

Power BI案例-连锁糕点店数据集的仪表盘制作

Power BI案例-连锁糕点店数据集的仪表盘制作 数据集描述 有一个数据集&#xff0c;包含四张工作簿&#xff0c;每个工作簿是一张表&#xff0c;其中可以销售表可以划分为事实表&#xff0c;产品表&#xff0c;日期表和门店表为维度表。 工作簿名称、字段含义和数据集的对应关…

Java入门学习笔记二

一、抽象类 当编写一个类时&#xff0c;我们往往会为该类定义一些方法&#xff0c;这些方法是用来描述该类的行为方式&#xff0c;那么这些方法都有具体的方法体。 分析事物时&#xff0c;发现了共性内容&#xff0c;就出现向上抽取。会有这样一种特殊情况&#xff0c;就是功…

《一书读懂物联网》前言

我们对知识的认知是有规律可循的&#xff0c;大都是从问题开始&#xff0c;对问题的界定、归纳等都是为解决知识增长或进化而服务的&#xff0c;正如波普尔知识进化图&#xff08;见图 i-1&#xff09;所示的那样。 科学始于问题&#xff0c;发现问题是科学知识增长的起点&…

从开源项目中学习如何自定义 Spring Boot Starter 小组件

前言 今天参考的开源组件Graceful Response——Spring Boot接口优雅响应处理器。 具体用法可以参考github以及官方文档。 基本使用 引入Graceful Response组件 项目中直接引入如下maven依赖&#xff0c;即可使用其相关功能。 <dependency><groupId>com.feiniaoji…

加速数据采集:用OkHttp和Kotlin构建Amazon图片爬虫

引言 曾想过轻松获取亚马逊上的商品图片用于项目或研究吗&#xff1f;是否曾面对网络速度慢或被网站反爬虫机制拦截而无法完成数据采集任务&#xff1f;如果是&#xff0c;那么本文将为您介绍如何用OkHttp和Kotlin构建一个高效的Amazon图片爬虫解决方案。 背景介绍 亚马逊&a…