0028算法笔记——【回溯法】批作业调度问题和符号三角形问题

合集下载

算法设计与分析——批处理作业调度(回溯法)

算法设计与分析——批处理作业调度(回溯法)

算法设计与分析——批处理作业调度(回溯法)之前讲过⼀个相似的问题流⽔作业调度问题,那⼀道题最开始⽤动态规划,推到最后得到了⼀个Johnson法则,变成了⼀个排序问题,有兴趣的可以看⼀下本篇博客主要参考⾃⼀、问题描述给定n个作业的集合{J1,J2,…,Jn}。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为t ji。

对于⼀个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

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

例:设n=3,考虑以下实例:看到这⾥可能会对这些完成时间和是怎么计算出来的会有疑问,这⾥我拿123和312的⽅案来说明⼀下。

对于调度⽅案(1,2,3)作业1在机器1上完成的时间是2,在机器2上完成的时间是3作业2在机器1上完成的时间是5,在机器2上完成的时间是6作业3在机器1上完成的时间是7,在机器2上完成的时间是10所以,作业调度的完成时间和= 3 + 6 + 10这⾥我们可以思考⼀下作业i在机器2上完成的时间应该怎么去求?作业i在机器1上完成的时间是连续的,所以是直接累加就可以。

但对于机器2就会产⽣两种情况,这两种情况其实就是上图的两种情况,对于(1,2,3)的调度⽅案,在求作业2在机器2上完成的时间时,由于作业2在机器1上还没有完成,这就需要先等待机器1处理完;⽽对于(3,1,2)的调度⽅案,在求作业2在机器2上完成的时间时,作业2在机器1早已完成,⽆需等待,直接在作业1被机器1处理之后就能接着被处理。

综上,我们可以得到如下表达式if(F2[i-1] > F1[i])F2[i] = F2[i-1] + t[2][i]elseF2[i] = F1[i] + t[2][i]⼆、算法设计类Flowshop的数据成员记录解空间的结点信息,M输⼊作业时间,bestf记录当前最⼩完成时间和,数组bestx记录相应的当前最佳作业调度。

有期限的作业调度算法doc

有期限的作业调度算法doc

有期限的作业调度算法一、典型算法贪心算法是以局部最优为原则,通过一系列选择来得到问题的一个最优解,它所做的每一个选择都是当前状态下某种意义上的最佳选择.贪心算法适合于解决这样的问题:局部的最优解能够导致最终结果的最优解。

“有限期作业安排问题”描述如下:有n个任务每个任务Ji都有一个完成期限di,若任务Ji在它的期限di内完成,则可以获利Ci(l[i[n);问如何安排使得总的收益最大(假设完成每一个任务所需时间均为一个单位时间).这个问题适合用贪心算法来解决,贪心算法的出发点是每一次都选择利润大的任务来完成以期得到最多的收益;但是对于本问题由于每一个任务都有一个完成的期限因此在任务安排过程中除了考虑利润Ci外,还要考虑期限di.(一)算法描述1.假设用数组J存储任务,用数组C存储利润,用数组d存储期限,用数组P存储安排好的任务.按照利润从大到小的次序,调整任务的次序:对n个任务J1,J2,...,Jn进行调整,使其满足C1三C2三…三Cn.2.将排序后的任务顺次插入输出数组P.A)任务J[1]排在P[1];B)若已经优先安排了k个任务,则它们满足d[P[i]]三i(1WiWk),即利润较高的k个任务能够在它们的期限内完成•那么,对于第k+1个任务J[k+1],显然C[k+1]WC[i](1WiWk);比较d[k+1]和d[P[k]]:a)若d[k+1]大于d[P[k]],那么将它排在第k+1位(P[k+1]T[k+1]);b)若d[k+1]小于等于d[P[k]],那么,J[k]能否插入,需比较k和d[P[k]]而定:i)若k等于d[P[k]](其第k个任务已经排在可以满足的最迟时间),那么,因为Ck^Ck+1,只好放弃任务J[k+1];ii)若k小于d[P[k]](表示第k个任务还有推后的余地):若d[k+1]=k,将第k个任务后移一位(P[k+1]-P[k]),将第k+1个任务排在第k位(P[k]一J[k+1]).若d[k+1]<k,则继续比较任务J[k+1]与第k-1个任务,方法同上.C)重复B)直至处理完最后一个任务.3)输出P.(二)算法实现voidjob-arrangement(char*J[],intd[],intC[],intP[],intn){sort(C,J,d,n);/*按照降序调整数组C,同时对数组J!d作相应调整*/P[0]=0;d[0]=0;P[1]=1;k=1;for(i=2;i<=n;i++){r=k;while{(d[P[r]]>=d[i])&&d[P[r]]!=r}r--;if(d[P[r]]<d[i])for(h=k;h>r;h--)P[h+1]=P[h];k++;P[r+1]=i;}output(P,J,n)}(三)算法分析该算法在最坏情况下的时间复杂度是0(n?),在最好情况下的是0(n)二.利用UNION与FIND进行作业排序利用不相交集合的UNION与FIND算法以及使用一个不同的方法来确定部分解的可行性。

0018算法笔记——【动态规划】流水作业调度问题与Johnson法则

0018算法笔记——【动态规划】流水作业调度问题与Johnson法则

1、问题描述:n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。

每个作业加工的顺序都是先在M1上加工,然后在M2上加工。

M1和M2加工作业i所需的时间分别为ai和bi。

流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。

2、问题分析直观上,一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。

在一般情况下,机器M2上会有机器空闲和作业积压2种情况。

设全部作业的集合为N={1,2,…,n}。

S是N的作业子集。

在一般情况下,机器M1开始加工S中作业时,机器M2还在加工其他作业,要等时间t后才可利用。

将这种情况下完成S中作业所需的最短时间记为T(S,t)。

流水作业调度问题的最优值为T(N,0)。

设π是所给n个流水作业的一个最优调度,它所需的加工时间为aπ(1)+T’。

其中T’是在机器M2的等待时间为bπ(1)时,安排作业π(2),…,π(n)所需的时间。

记S=N-{π(1)},则有T’=T(S,bπ(1))。

证明:事实上,由T的定义知T’>=T(S,bπ(1))。

若T’>T(S,bπ(1)),设π’是作业集S在机器M2的等待时间为bπ(1)情况下的一个最优调度。

则π(1),π'(2),…,π'(n)是N的一个调度,且该调度所需的时间为aπ(1)+T(S,bπ(1))<aπ(1)+T’。

这与π是N的最优调度矛盾。

故T’<=T(S,bπ(1))。

从而T’=T(S,bπ(1))。

这就证明了流水作业调度问题具有最优子结构的性质。

由流水作业调度问题的最优子结构性质可知:从公式(1)可以看出,该问题类似一个排列问题,求N个作业的最优调度问题,利用其子结构性质,对集合中的每一个作业进行试调度,在所有的试调度中,取其中加工时间最短的作业做为选择方案。

将问题规模缩小。

批处理作业调度 回溯法

批处理作业调度  回溯法

批处理作业调度问题描述:N个作业要在两台机器上处理,每个作业必须先由机器1处理,然后再由机器2处理,机器1处理作业i所需时间为ai,机器2处理作业i所需时间为bi,批处理作业调度问题要求确定这n个作业的最优处理顺序,使得到处理结束所需的时间和最少。

输入:输出:最节省时间为25 应对方案为 1 3 2算法描述:回溯法按深度优先策略搜索问题的解空间树。

首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。

如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。

剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。

解空间树分为两种:子集树和排列树。

两种在算法结构和思路上大体相同。

算法设计:设数组a[n]存储n个作业在机器1上的处理时间,数组b[n]存储n个作业在机器2上的处理时间。

数组x[n]存储具体的作业调度,初始迭代时x[0]表示未安排作业,x[k]表示第k个作业的编号。

数组sum1[n]存储机器1的完成时间,sum2[n]存储机器2的完成时间,初始迭代时sum1[0]和sum2[0]均为0,表示完成时间均为0,sum1[k]表示在安排第k个作业后机器1的当前完成时间,sum2[k]表示在安排第k个作业后机器2的当前完成时间举例:有三个作业1, 2, 3,这三个作业在机器1上所需的处理时间为(2, 5, 4),在机器2上所需的处理时间为(3, 2, 1),确定这n个作业的最优处理顺序,使得到处理结束所需的时间和最少。

确定这3个作业的最优处理顺序,使得到处理结束所需的时间和最少。

由此可知,最优处理顺序为(1,2,3)和(2,1,3)最短完成时间为12#include <iostream>using namespace std;#define MAX 200int* x1;//作业Ji在机器1上的工作时间;int* x2;//作业Ji在机器2上的工作时间;int number=0;//作业的数目;int* xOrder;//作业顺序;int* bestOrder;//最优的作业顺序;int bestValue=MAX;//最优的时间;int xValue=0;//当前完成用的时间;int f1=0;//机器1完成的处理时间;int* f2;//第i阶段机器2完成的时间;void BackTrace(int k){if (k>number){for (int i=1;i<=number;i++){bestOrder[i]=xOrder[i];}bestValue=xValue;}{for (int i=k;i<=number;i++){f1+=x1[xOrder[i]];f2[k]=(f2[k-1]>f1?f2[k-1]:f1)+x2[xOrder[i]];xValue+=f2[k];swap(xOrder[i],xOrder[k]);if (xValue<bestValue){BackTrace(k+1);}swap(xOrder[i],xOrder[k]);xValue-=f2[k];f1-=x1[xOrder[i]];}}}int main(){int i;cout<<"请输入作业数目:";cin>>number;x1=new int[number+1];x2=new int[number+1];xOrder=new int[number+1];bestOrder=new int[number+1];f2=new int[number+1];x1[0]=0;x2[0]=0;xOrder[0]=0;bestOrder[0]=0;f2[0]=0;cout<<"请输入每个作业在机器1上所用的时间:"<<endl; for (int i=1;i<=number;i++){cout<<"第"<<i<<"个作业=";cin>>x1[i];}cout<<"请输入每个作业在机器2上所用的时间:"<<endl; for (i=1;i<=number;i++){cout<<"第"<<i<<"个作业=";cin>>x2[i];}for (i=1;i<=number;i++){xOrder[i]=i;}BackTrace(1);cout<<"最节省的时间为:"<<bestValue;cout<<endl;cout<<"对应的方案为:";for (i=1;i<=number;i++){cout<<bestOrder[i]<<" ";}System (“pause”);return 0;}。

计算复杂性之回溯法.

计算复杂性之回溯法.

回溯法2
摘要:排列回溯 应用于:汉密尔顿路径问题 和平皇后问题
排列
问题:生成n个不同数字的所有排列。 解决方案: 1.经过所有的长度为n的n元字符串,剪除所有的非排列。 2.设一个布尔数组U[1..n],如果m是未用的,U[m]是ture。 3.用一个数组A[1..n]来表示当前的排列。 4.目的是调用process(a),一旦A[1..n]包含当前排列。 调用程序permute(n): procedure permute(m) comment process all perms of length m 1. if m = 0 then process(A) else 2. for j := 1 to n do 这里和前面的汉密尔 3. if U[j] then 顿环问题是一样的。 4. U[j]:=false 一个汉密尔顿环就是 5. A[m] := j; permute(m− 1) 图像节点的一个排列。 6. U[j]:=true
ቤተ መጻሕፍቲ ባይዱ举搜索
穷举搜索,顾名思义,就是尝试所求问题的所有可能性。 穷举搜索的时间往往很慢,但也有一些关于标准的工具来帮 助我们使用:生成基本项目的算法,比如: 1.长度为n的二进制字符串共有2n个字符。 2.长度为n的k-ary字符串有kn个字符 3.n!种排列方式 4.在n样事物中选取r件事物,共有n!/r!(n-r)!种组合。 回溯法可以通过“优化修剪”的方法加速穷举搜索。
回溯基本问题1、位串问题
问题:生成含有n个字符的所有字符串。 解题思路:使用分治法。用数组A[1..n]来保存当前的二进制 字符串。目的是调用process(A)一次,用数组A[1..n]保存 每个二进制字符串。 伪代码: Procedure binary(m ) comment process all binary strings of length m if m =0 then process(A ) else A [m ]:=0;binary(m − 1) A [m ]:=1;binary(m − 1)

分支限界法-批处理调度问题

分支限界法-批处理调度问题

【分支限界法】批处理作业调度问题问题描述给定n个作业的集合J1,J2,…,J。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为tji。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的个作业,制定最佳作业调度方案,使其完成时间和达到最小例:设n=3,考虑以下实例:作业作业作业这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。

限界函数批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排在作业调度问相应的排列空间树中,每一个节点E都对应于一个已安排的作业集,……〈。

以该节点为根的子树中所含叶节点的完成时间和可表示为:设|M|=r,且L是以节点E为根的子树中的叶节点,相应的作业调度为{pk,k=1,2,……1其中pk是第k个安排的作业。

如果从节点E到叶节点L的路上,每一个作业pk在机器1上完成处理后都能立即在机器2上开始处理,即从p r+1开始,机器1没有空闲时间,则对于该叶节点L有:Z七=2 [耳心+(〃-左+1居网+%热]=d£叩+1i更M注:(n-k+1)tipk因为是完成时间和,所以,后续的n-k+1)个作业完成时间和都得算上ipk。

如果不能做到上面这一点,则si只会增加,从而有:下;, 一」。

类似地,如果从节点E开始到节点L的路上,从作业p r+1开始,机器2没有空闲时间,则:日25;E [max(勺,/+呻4) + ("4 + 1H热]k=r+l冈同理可知,s2是三;•的下界。

由此得到在节点E处相应子树中叶节点完成时间和的下界是:/吓 J+maxf3}ieM注意到如果选择Pk,使tipk在k>=r+1时依非减序排列,S1则取得极小值。

分支限界法解批处理作业调度问题java

分支限界法解批处理作业调度问题java

作业调度问题是指在多道程序系统中,根据各道程序的特点和系统的资源状况,合理地安排各道程序的执行顺序。

而分支限界法是一种解决排列、组合、0-1背包等问题的常用技术,可以有效地解决作业调度问题。

本文将结合Java语言,介绍如何使用分支限界法来解决作业调度问题。

一、作业调度问题的基本概念1. 作业调度问题的定义作业调度是指计算机系统对各种作业的安排和分配,以便使计算机系统有效地利用资源,提高各类作业的完成时间和各项资源的利用率。

2. 作业调度问题的类型作业调度问题主要分为单机调度和并行机调度两种类型。

其中单机调度是指一个作业在一台机器上进行处理,而并行机调度是指多个作业在多台机器上进行处理。

3. 作业调度问题的目标作业调度问题的主要目标是减少作业的等待时间,提高系统吞吐量,提高资源利用率,减少作业的周转时间等。

二、分支限界法的基本原理1. 分支限界法的概念分支限界法是一种剪枝技术,通过遍历搜索所有可能的解空间,并在搜索过程中剪掉某些明显不可能得到最优解的分支,从而有效地降低了搜索空间的规模。

2. 分支限界法的特点分支限界法在搜索过程中,通过剪枝操作,能够大大降低搜索空间的规模,提高搜索效率。

在解决NP难问题时,分支限界法通常能够得到较为满意的解。

3. 分支限界法的应用分支限界法被广泛应用于排列、组合、0-1背包、作业调度等各种组合优化问题的求解过程中,具有较高的实用性和效率。

三、分支限界法解决作业调度问题的具体步骤1. 确定问题的数学模型需要将作业调度问题转化为数学模型,例如采用Gantt图或者某种数学表达形式来描述作业的调度顺序和资源分配情况。

2. 设计合适的状态空间树根据问题的特点,设计合适的状态空间树来表示各种可能的作业调度方案,并利用分支限界法进行搜索。

3. 利用分支限界法进行搜索对设计好的状态空间树进行搜索,通过适当的剪枝操作,降低搜索空间的规模,提高搜索效率,直到找到最优解或者满意解为止。

作业调度问题.ppt

作业调度问题.ppt
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(f)14
a2
j2
j1
a0
j0
b0
b2
a1
b1
j2
a2 b2
a1 b1
j1
a0
b0
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14
a2 b2
j2
a1 b1
a3 b3
a2
b2
j2
a1
b1
j1
a0
j0
b0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
j3
a2
j2
a3
b3
b2
a1
b1
j1
a0
j0
b0
a4 b4
j4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
(a)12
(b)14
(c)13
j2
a1
j1
a0 b0
j0
a2 b2 b1
j2
a2
b2
j1 a1 b1
j0
a0 b0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(d)12
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(e)15
a2 b2
j2
j1
a1
b1
a0 b0
j1
a0
b0
j0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1、批作业调度问题(1)问题描述给定n个作业的集合{J1,J2,…,Jn}。

每个作业必须先由机器1处理,然后由机器2处理。

作业Ji需要机器j的处理时间为tji。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。

所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

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

例:设n=3,考虑以下实例:这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。

(2)算法设计批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排列树。

按照回溯法搜索排列树的算法框架,设开始时x=[1,2,……n]是所给的n个作业,则相应的排列树由x[1:n]的所有排列构成。

算法具体代码如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Flowshop6.{7.friend int Flow(int **M,int n,int bestx[]);8.private:9.void Backtrack(int i);10.11.int **M, // 各作业所需的处理时间12. *x, // 当前作业调度13. *bestx, // 当前最优作业调度14.15. *f2, // 机器2完成处理时间16. f1, // 机器1完成处理时间17. f, // 完成时间和18.19. bestf, // 当前最优值20. n; // 作业数21. };22.23.int Flow(int **M,int n,int bestx[]);24.25.template <class Type>26.inline void S &a, Type &b);27.28.int main()29.{30.int n=3,bf;31.int M1[4][3]={{0,0,0},{0,2,1},{0,3,1},{0,2,3}};32.33.int **M=new int*[n+1];34.35.for(int i=0;i<=n;i++)36. {37. M[i]=new int[3];38. }39. cout<<"M(i,j)值如下:"<<endl;40.41.for(int i=0;i<=n;i++)42. {43.for(int j=0;j<3;j++)44. {45. M[i][j]=M1[i][j];46. }47. }48.49.int bestx[4];50.for(int i=1;i<=n;i++)51. {52. cout<<"(";53.for(int j=1;j<3;j++)54. cout<<M[i][j]<<" ";55. cout<<")";56. }57.58. bf=Flow(M,n,bestx);59.60.for(int i=0;i<=n;i++)61. {62.delete []M[i];63. }64.delete []M;65.66. M=0;67.68. cout<<endl<<"最优值是:"<<bf<<endl;69. cout<<"最优调度是:";70.71.for(int i=1;i<=n;i++)72. {73. cout<<bestx[i]<<" ";74. }75. cout<<endl;76.return 0;77.}78.79.void Flowshop::Backtrack(int i)80.{81.if (i>n)82. {83.for (int j=1; j<=n; j++)84. {85. bestx[j] = x[j];86. }87. bestf = f;88. }89.else90. {91.for (int j = i; j <= n; j++)92. {93. f1+=M[x[j]][1];94.//机器2执行的是机器1已完成的作业,所以是i-195. f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];96.97. f+=f2[i];98.if (f < bestf)//剪枝99. {100. Swap(x[i], x[j]); 101. Backtrack(i+1); 102. Swap(x[i], x[j]); 103. }104. f1-=M[x[j]][1];105. f-=f2[i];106. }107. }108.}109.110.int Flow(int **M,int n,int bestx[]) 111.{112.int ub=30000;113.114. Flowshop X;115. X.n=n;116. X.x=new int[n+1];117. X.f2=new int[n+1];118.119. X.M=M;120. X.bestx=bestx;121. X.bestf=ub;122.123. X.f1=0;124. X.f=0;125.126.for(int i=0;i<=n;i++)127. {128. X.f2[i]=0,X.x[i]=i;129. }130. X.Backtrack(1);131.delete []X.x;132.delete []X.f2;133.return X.bestf;134.}135.136.template <class Type>137.inline void S &a, Type &b)138.{139. Type temp=a;140. a=b;141. b=temp;142.}由于算法Backtrack在每一个节点处耗费O(1)计算时间,故在最坏情况下,整个算法计算时间复杂性为O(n!)。

程序运行结果如下:2、符号三角形问题(1)问题描速下图是由14个“+”和14个“-”组成的符号三角形。

2个同号下面都是“+”,2个异号下面都是“-”。

在一般情况下,符号三角形的第一行有n个符号。

符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。

(2)算法设计解向量:用n元组x[1:n]表示符号三角形的第一行。

当x[i]=1时表示符号三角形第一行的第i个符号为"+";当i=0时,表示符号三角形第一行的第i个符号为"-";1<=x<=n。

由于x[i]是二值的,所以可以用一棵完全二叉树来表示解空间。

可行性约束函数:在符号三角形的第一行前i个符号x[1:i]确定后,就确定了一个由i(i+1)/2个符号组成的符号三角形。

下一步确定x[i+1]的值后,只要在前面已确定的符号三角形的右边加一条边,就可以扩展为x[1:i+1]所相应的符号三角形。

最终由x[1:n]所确定的符号三角形中包含"+"号个数与"-"个数同为n(n+1)/4。

因此,当前符号三角形所包含的“+”个数与“-”个数均不超过n*(n+1)/4 。

无解的判断:对于给定的n,当n*(n+1)/2为奇数时,显然不存在包含的"+"号个数与"-"号个数相同的符号三角形。

此时,可以通过简单的判断加以处理。

程序的具体代码如下:[cpp]view plain copy1.#include "stdafx.h"2.#include <iostream>ing namespace std;4.5.class Triangle6.{7.friend int Compute(int);8.private:9.void Backtrack(int i);10.int n, //第一行的符号个数11. half, //n*(n+1)/412. count, //当前"+"号个数13. **p; //符号三角矩阵14.long sum; //已找到的符号三角形数15.};16.17.int Compute(int n);18.19.int main()20.{21.for(int n=1;n<=10;n++)22. {23. cout<<"n="<<n<<"时,共有"<<Compute(n);24. cout<<"个不同的符号三角形。

"<<endl;25. }26.return 0;27.}28.29.void Triangle::Backtrack(int t)30.{31.if ((count>half)||(t*(t-1)/2-count>half))32. {33.return;34. }35.36.if (t>n)37. {38. sum++;39. }40.else41. {42.for (int i=0;i<2;i++)43. {44. p[1][t]=i;//第一行符号45. count+=i;//当前"+"号个数46.47.for(int j=2;j<=t;j++)48. {49. p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2];50. count+=p[j][t-j+1];51. }52. Backtrack(t+1);53.for (int j=2;j<=t;j++)54. {55. count-=p[j][t-j+1];56. }57. count-=i;58. }59. }60.}61.62.int Compute(int n)63.{64. Triangle X;65. X.n=n;66. X.count=0;67. X.sum=0;68.69. X.half=n*(n+1)/2;70.if(X.half%2==1)return 0;71. X.half=X.half/2;72.73.int**p=new int*[n+1];74.75.for(int i=0;i<=n;i++)76. {77. p[i]=new int[n+1];78. }79.80.for(int i=0;i<=n;i++)81. {82.for(int j=0;j<=n;j++)83. {84. p[i][j]=0;85. }86. }87.88. X.p=p;89. X.Backtrack(1);90.for(int i=0;i<=n;i++)91. {92.delete []p[i];93. }94.delete []p;95. p=0;96.return X.sum;97.}计算可行性约束需要O(n)时间,在最坏情况下有O(2^n)个结点需要计算可行性约束,故解符号三角形问题的回溯算法所需的计算时间为O(n2^n)。

相关文档
最新文档