实验4 回溯法
回溯法(马周游问题)——实验报告
华南师范大学本科生实验报告姓名_黎国庄_学号20062101247院系_计算机学院专业_计算机科学与技术年级2006级班级_2班_小组实验任务分工_独立完成实验时间2008 年_6_月 3 _日实验名称回溯法的应用指导老师及职称陈卫东老师华南师范大学教务处编印实验课程:算法分析与设计实验名称:回溯法的应用(综设型实验)第一部分实验内容1.实验目标(1)熟悉使用回溯法求解问题的基本思路。
(2)掌握回溯算法的程序实现方法。
(3)理解回溯算法的特点。
2. 实验任务(1)从所给定的题目中选择一题,使用回溯法求解之。
(2)用文字来描述你的算法思路,包括解空间、限界函数、算法主要步骤等。
(3)在Windows环境下使用C/C++语言编程实现算法。
(4)记录运行结果,包括输入数据,问题解答及运行时间。
(5)分析算法最坏情况下时间复杂度和空间复杂度。
(6)谈谈实验后的感想,包括关于该问题或类似问题的求解算法的建议。
3. 实验设备及环境PC;C/C++等编程语言。
4. 实验主要步骤(1)根据实验目标,明确实验的具体任务;(2)设计求解问题的回溯算法,并编写程序实现算法;(3)设计实验数据并运行程序、记录运行的结果;(4)分析算法时空性能;(5)实验后的心得体会。
第二部分问题及算法1.问题描述给出一个8×8的棋盘,一个放在棋盘某个位置上的马(规定马的走法为走“日”)是否可以恰好访问每个方格一次,并回到起始位置上?2. 回溯法的一般思路对于马所在其中一格时,它可以走的位置有以下8种情况:⑧①⑦②马⑥③⑤④所以对于每一个马所在的格子里,马可以走对应的8个方向。
用满8叉树,每一个子树对应马可跳的方向当要走下一子树(跳下一格)时,该子树可走(还没有走过并且在棋盘里边),即沿该方向走下去,当不可以走,即回溯到上一步,选择另一方向往下走;当该子树的8个子棋都遍历完了(即8个方向都走过了),则回溯到它父亲那里。
重复一直做下去,到棋盘每个格子都走过一遍,而且回到出发点或者找不到路径即结束。
实验报告4.回溯算法
算法设计与分析实验报告实验名称_____回溯算法_____学院________数学与计算机学院____ 班级_______信科00000___________ 学号_______6666666666__________ 姓名_____000000________________ 2016年月日{if(((a+b)==24)||((a-b)==24)||((a*b)==24)||(b!=0&&a%b==0&&a/b==24)){//如果经过上面的计算得到解while(!route.empty()){node now=route.front();printf("%d%c%d=%d\n",now.a,now.oper,now.b,now.sum);//依次输出前面的计算过程route.pop();}if((a+b)==24){if(b>a) swap(a,b);printf("%d+%d=%d\n",a,b,a+b);}if((a-b)==24) printf("%d-%d=%d\n",a,b,a-b);if((a*b)==24) {if(b>a) swap(a,b);printf("%d*%d=%d\n",a,b,a*b);}if(a%b==0&&b!=0&&(a/b)==24) printf("%d/%d=%d\n",a,b,a/b);//a/b比较特殊,要求结果必须是整数flag=true;//表示找到解,一旦找到任何一个解就退出}return ;}queue <node> temp=route;node x;x.a=a,x.b=b,x.sum=a+b,x.oper='+';if(b>a) swap(x.a,x.b);temp.push(x);dfs(cur+1,a+b,num[cur+1],temp);//(((a*b)*c)*d) 模型temp=route;x.a=a,x.b=b,x.sum=a*b,x.oper='*';if(b>a) swap(x.a,x.b);temp.push(x);dfs(cur+1,a*b,num[cur+1],temp);temp=route;x.a=a,x.b=b,x.sum=a-b,x.oper='-';temp.push(x);dfs(cur+1,a-b,num[cur+1],temp);if(b!=0&&a%b==0){//a/b需要验证合法性temp=route;x.a=a,x.b=b,x.sum=a/b,x.oper='/';temp.push(x);dfs(cur+1,a/b,num[cur+1],temp);}temp=route;x.a=b,x.b=num[cur+1],x.sum=b+num[cur+1],x.oper='+';if(x.b>x.a) swap(x.a,x.b);temp.push(x);dfs(cur+1,a,b+num[cur+1],temp);//a*((b*c)*d) 模型temp=route;x.a=b,x.b=num[cur+1],x.sum=b*num[cur+1],x.oper='*';if(x.b>x.a) swap(x.a,x.b);temp.push(x);dfs(cur+1,a,b*num[cur+1],temp);temp=route;x.a=b,x.b=num[cur+1],x.sum=b-num[cur+1],x.oper='-';temp.push(x);dfs(cur+1,a,b-num[cur+1],temp);if(num[cur+1]!=0&&b%num[cur+1]==0) {temp=route;x.a=b,x.b=num[cur+1],x.sum=b/num[cur+1],x.oper='/';temp.push(x);dfs(cur+1,a,b/num[cur+1],temp);}}int main(){//freopen("point24.in","r",stdin);//输入输出重定向//freopen("point24.out","w",stdout);queue <node> t;scanf("%d %d %d %d",&num[0],&num[1],&num[2],&num[3]);while(!flag){dfs(1,num[0],num[1],t);printf("%d %d %d %d\n",num[0],num[1],num[2],num[3]);if(!next_permutation(num,num+4)) break;}if(!flag) printf("No answer!\n");system("pause");return 0;}。
实验四 回溯法(图着色问题)
01 234 001 1 01 1 1 01 01 21 1 01 0 3001 01 41 1 01 0
class MGraph { public:
MGraph(int v,int s); void mColoring(int m,int *x); //一维数组x,存放1~n个顶点的颜色 ~MGraph(); private: void NextValue(int k,int m,int *x); void mColoring (int k,int m,int *x); int **a; //二维数组a,存储图的邻接矩阵 int n,e; //n表示图的顶点数,e表示边数 };
无向图G
【实验内容与要求】
图的着色问题:设G=(V,E)是一连通无向图,有3 种颜色,用这些颜色为G的各顶点着色,每个顶点着 一种颜色,且相邻顶点颜色不同。试用回溯法设计一 个算法,找出所有可能满足上述条件的着色法。
无向图G
无向图G
对应这个无向图的状态空间树应该是怎样的?
是一个完全3叉树,共6层
实验四 回溯法 — 图的着色问题
图的着色问题是由地图的着色问题引申而来的: 用m种颜色为地图着色,使得地图上的每一个 区域着一种颜色,且相邻区域颜色不同。
问题处理:如果把每一个区域收缩为一个顶点, 把相邻两个区域用一条边相连接,就可以把一
个区域图抽象为一个平面图。
地图(map)中地区的相邻关系,在图(graph )中用边表示。
//若(i, j)是图的边,且相邻结点k和j颜色相同 //发生冲突,选下一种颜色
if (j==k) return; //成功选择一种颜色返回 }while (1); //循环尝试颜色 }
运行结果:
实验四 回溯法
实验四回溯法(4学时)上机实验一般应包括以下几个步骤:(1)、准备好上机所需的程序。
手编程序应书写整齐,并经人工检查无误后才能上机。
(2)、上机输入和调试自己所编的程序。
一人一组,独立上机调试,上机时出现的问题,最好独立解决。
(3)、上机结束后,整理出实验报告。
实验报告应包括:题目、程序清单、运行结果、对运行情况所作的分析。
一、实验目的与要求1.掌握回溯法的基本思想方法;理解回溯法的基本思想,理解回溯法算法的两个基本要素最优子结构性质和子问题的重叠性质。
熟练掌握典型的回溯法问题。
2.了解适用于用回溯法求解的问题类型,并能设计相应回溯法算法;3.掌握回溯法算法复杂性分析方法分析问题复杂性。
二、实验内容(以下题目要求采用回溯法算法完成):1、N皇后问题八皇后问题是十九世纪著名的数学家高斯于1850年提出的。
问题是:在8×8的棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
可以把八皇后问题扩展到n皇后问题,即在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能处于同一行、同一列或同一斜线上。
如下图所示:其中图中的一个解为:4 6 8 2 7 1 3 5N皇后问题(含八皇后问题的扩展,规则同八皇后):在N*N的棋盘上,放置N个皇后,要求每一横行每一列,每一对角线上均只能放置一个皇后,求解可能的方案及方案数。
1.运用回溯法,设计解决上述问题的算法,设计出用回溯法计算出在N*N的棋盘上,放置N个皇后,要求每一横行每一列,每一对角线上均只能放置一个皇后,并返回每个皇后的位置。
2.掌握回溯算法的应用。
2、0-1背包问题给定n种物品和一背包。
物品i的重量是wi>0,其价值为vi>0,背包的容量为c。
问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?利用回溯法试设计一个算法求出0-1背包问题的解,也就是求出一个解向量xi(xi = 0 或1,xi = 0表示物体i不放入背包,xi =1表示把物体i放入背包),3、装载问题有两艘船,它们的可装载的货物重量分别为才c1,c2,给定一批货物,其重量保存在数组w 【i】中了,问这批货物能否用此两艘船送出。
回溯法的应用(实验报告)
华南师范大学本科生实验报告姓名_张俊发_学号***********院系_计算机学院_专业_计算机科学与技术_年级2008级班级_2班_小组实验任务分工_独立完成实验时间2010 年_6_月 1 _日实验名称回溯法的应用指导老师及职称陈振洲华南师范大学教务处编印实验课程:算法分析与设计实验名称:回溯法的应用(综设型实验)第一部分实验内容1.实验目标(1)熟悉使用回溯法求解问题的基本思路。
(2)掌握回溯算法的程序实现方法。
(3)理解回溯算法的特点。
2. 实验任务(1)从所给定的题目中选择一题,使用回溯法求解之。
(2)用文字来描述你的算法思路,包括解空间、限界函数、算法主要步骤等。
(3)在Windows环境下使用C/C++语言编程实现算法。
(4)记录运行结果,包括输入数据,问题解答及运行时间。
(5)分析算法最坏情况下时间复杂度和空间复杂度。
(6)谈谈实验后的感想,包括关于该问题或类似问题的求解算法的建议。
3. 实验设备及环境PC;C/C++等编程语言。
4. 实验主要步骤(1)根据实验目标,明确实验的具体任务;(2)设计求解问题的回溯算法,并编写程序实现算法;(3)设计实验数据并运行程序、记录运行的结果;(4)分析算法时空性能;(5)实验后的心得体会。
第二部分问题及算法1.问题描述国际象棋的棋盘上有八八六十四个格子(这里简化为5*6=30个格子), 黑白相间, 棋子放在格子中. 棋中的马走“日”字, 即横二竖一, 或横一竖二. 马从棋盘的某个格子出发, 走29 步, 是否能走过其他29 个格子各一次? 如果能够, 则说存在一条马的周游路线. 如果马从某个格子出发, 不重复地走过了其余29个格子, 第30 步又回到了出发点, 则说存在一条马的周游闭路.按照从上到下,从左到右对棋盘的方格编号,如下所示:1 2 3 4 5 67 8 9 10 11 1213 14 15 16 17 1819 20 21 22 23 2425 26 27 28 29 30马的走法是“日”字形路线,例如当马在位置15的时候,它可以到达2、4、7、11、19、23、26和28。
实验4 回溯算法
《算法设计与分析》实验报告实验4 回溯算法一、实验目的:掌握回溯算法的设计思想与设计方法。
二、实验环境1、硬件环境CPU:Intel(R) Celeron(R) CPU 1007U @ 1.5GHz内存:4G硬盘:500G2、软件环境操作系统:Windows7编程环境:Visual C++ 6.0编程语言:C三、实验内容1、问题有一个背包,最大限重为C,有n个物品,重量分别为W=<w1, w2, …, w n>,要求找出一个装载方案,使得放入背包物品的重量最大。
输出装载方案和该方案下的背包所装物品总重量。
2、数据结构(1)解的结构一维数据(1)<0 1 0 1 1 1 1>(2) <0 0 1 0 1 1 0>(2)搜索空间的结构3、算法伪代码ReBack(i)1、If i>n then<x1,x2,x3,...xn>是解2、Else while Si≠∅do3、Xi Si中最小值4、SiSi-{Xi}5计算Si+16ReBack(i+1)4、算法分析时间复杂度:O(2n)空间复杂度:O(n)5、关键代码(含注释)#include<stdio.h>int n,c,bestp;//物品的个数,背包的容量,最大重量int w[10000],x[10000],bestx[10000];//w[i]物品的重量,x[i]暂存物品的选中情况,bestx[i]物品的选中情况void Backtrack(int i,int cw){ //cw当前包内物品重量int j;if(i>n)//回溯结束{if(cw>bestp){bestp=cw;for(i=0;i<=n;i++) bestx[i]=x[i];}}elsefor(j=0;j<=1;j++){x[i]=j;if(cw+x[i]*w[i]<=c){cw+=w[i]*x[i];Backtrack(i+1,cw);cw-=w[i]*x[i];}}}6、实验结果(1)输入:C=152,n=7,W=<90, 80, 40, 30, 20, 12, 10> 输出:(2)输入:C=954,n=7,W=<2, 23, 163, 241, 311, 479, 487> 输出:四、实验总结(心得体会、需要注意的问题等)回溯算法也称试探法,是一种系统的搜索问题的解的方法。
实验四 回溯法的应用------跳马算法
实验四回溯法的应用------跳马算法学号:012124345 姓名:梁文耀一、实验目的掌握使用回溯法求解问题的基本思路;理解其特点。
二、实验思想算法的基本思路是:定义结构体:struct PLACE{int x, int y}表示棋盘上的位置。
依题意,马每跳一步之后都可以从七个不同的方向选择下一步的跳马,当然,前提是跳的这一步在棋盘内且它前面的任何一步都没跳到这一格子上(限界),就可以认为这一步跳成功,否则跳马不成功。
若跳马不成功,则找下一个方向尝试跳马,若七个方向都跳马不成功,则回溯。
假设棋盘的行(列)数为n。
在本算法中设置这样一个全局数组:c[8][2]={{2,1},{2,-1},{1,2},{1,-2},{-2,1},{-2,-1},{-1,2},{-1,-2}}; 来记录跳马的八个方向。
三、程序分析(主要算法)int map[12][12], status[12][12], kp;int start,finsh;int c[8][2]={{2,1},{2,-1},{1,2},{1,-2},{-2,1},{-2,-1},{-1,2},{-1,-2}};int flag = 0;void prt(int a[][12]) /* 打印棋盘状态*/{int i,j;printf("\n");for (i=2;i<=9;i++){for (j=2;j<=9;j++)printf("%4d",a[i][j]);printf("\n");}}void status2(void) /* 计算棋盘各点条件数*/ {int i,j,k,i2,j2,kz;for(i=0;i<12;i++)for(j=0;j<12;j++)status[i][j]=100;for(i=2;i<=9;i++)for(j=2;j<=9;j++){kz=0;for (k=0;k<=7;k++){i2=i+c[k][0];j2=j+c[k][1];if (map[i2][j2]<50) kz++;}status[i][j]=kz;}//prt(status);}void sort1(int b1[],int b2[]) /* 对8个可能的方向按条件数排序*/ {int i,j,mini,t; /*b1[]记录状态值(升序),b2[]记录排序后的下标*/ for (i=0;i<=7;i++){mini=i;for (j=i+1;j<=7;j++)if (b1[j]<b1[mini]) mini=j;t=b1[i]; b1[i]=b1[mini]; b1[mini]=t;t=b2[i]; b2[i]=b2[mini]; b2[mini]=t;}}void init1(void) /* 初始化*/{int i,j;for(i=0;i<12;i++)for(j=0;j<12;j++)map[i][j]=100;for(i=2;i<=9;i++)for(j=2;j<=9;j++)map[i][j]=0;status2();}void search(int i2,int j2) /* 利用递归回溯进行搜索*/ {if (flag == 1)return ;int b1[8],b2[8],i,i3,j3;kp++;for(i=0;i<=7;i++)//8个方向{b2[i]=i;b1[i]=status[i2+c[i][0]][j2+c[i][1]];}//forsort1(b1,b2);for(i=0;i<=7;i++)//检查是否可以走{i3=i2+c[b2[i]][0]; //按照排序中的方向查找j3=j2+c[b2[i]][1];if (map[i3][j3]==1 && kp==65){prt(map);flag = 1;}if (map[i3][j3]==0)//若有路可以走,则执行下面操作{map[i3][j3]=kp;search(i3,j3); //递归调用map[i3][j3]=0; //若还没有走完并且已经没有路走则恢复0状态}//if}//forkp--;//回朔}//searchint main(){int row, column;char ch;//int start,finsh;while (true){//打印提示信息cout<<" 1: 开始程序"<<endl;cout<<" 2: 退出程序"<<endl;cout<<"注意:"<<endl;cout<<""<<endl;cout<<"输入选择(1 或2):"<<endl;//如果输入信息不正确,继续输入do{ch = (char)_getch();}while(ch != '1' && ch != '2');system("cls");//选择3,返回if (ch == '2'){cout<<"退出!!!"<<endl;return 0;}//选择1,进入操作程序else{init1();cout<<"输入初始位置(行row)(1<=row<=8):"<<endl;cin>>row;row = row + 1;cout<<"输入初始位置(列column)(1<=column<=8):"<<endl;cin>>column;column = column + 1;map[row][column] = 1;kp = 1;start = clock();cout<<"遍历结果:"<<endl;search(row,column);flag = 0;finsh = clock();cout<<"算法运行时间:"<<finsh-start<<endl;kp = 1;}//结束cout<<endl<<"Press Any Key To Contimue:"<<endl;_getch();system("cls");}//whilereturn 0;}四、心得体会这程序和以前做的迷宫问题很相象,写起来不是很困难. 确定限界函数,在只有满足限界函数的前提下得到解,不满足限界条件时就要回溯,回到上一个节点,再从另外的方向出发。
算法实验四 回溯法
sum=0;
x=newint[n+1];
//尝试第一行的所有位置
for(inti=0;i<=n;i++)
x[i]=0;
backtrack(1);
returnsum;
}
privatestaticvoidbacktrack(intt) {
if(t>n)sum++;
else
for(inti=1;i<=n;i++){//从第一行开始往下放置,放置陈功继续
xi @{0,1},1<=i<=n
用回溯法解装载问题时,用子集树表示其解空间显然是最合适的。可行性约束函数可剪去不满足约束条件(
(w1x1+w2x2+...+wixi)<= c1)的子树。在子集树的第j+1层的节点Z处,用cw记当前的装载重量,即cw=(w1x1+w2x2+...+wjxj),当cw>c1时,以节点Z为根的子树中所有节点都不满足约束条件,因而该子树中解均为不可行解,故可将该子树剪去。
【算法描述】
importjava.util.Scanner;
publicclassNQueen {
staticintn;//皇后个数
staticintx[];//当前解,表示x[i]表示第i行皇后位置
staticlongsum;//当前已找到的可行方案数
publicstaticvoidmain(String[] args) {
1.首先将第一艘轮船尽可能装满。
2.将剩余的集装箱装上第二艘轮船。
将第一艘轮船尽可能的装满等价于选取全体集装箱的子集,使该子集中集装箱的重量之和最接近c1。因此,等价于一个特殊的0-1背包问题。因此是一棵子集树。
回溯法
算法实验报告四回溯法实验一、实验目的及要求利用回溯方法设计指派问题的算法,掌握回溯法的基本思想和算法设计的基本步骤。
要求:设计指派问题的回溯算法,注意回溯算法解决此问题要找出问题所有的可行解,然后一次比较保留问题的最优解(即最少耗费的解),并输出结果。
利用c语言(c++语言)实现算法,给出程序的正确运行结果。
(必须完成)指派问题描述:n个雇员被指派做n件工作,使得指派第i个人做第i件工作的耗费为ci,j,找出一种指派使得总耗费最少。
二、算法描述输入一个二维矩阵如下:352 4675 3374 5854 6其中行代表第几个雇员,列代表第几项工作,利用非递归的回溯算法实现,有主函数中定义k为第几个雇员,k的取值为集合{1,2,3,4}中元素。
且为行,列用a[k]表示,表示第几项工作。
定义耗费数组,一般项为c[i][j]],则c[k][a[k]]就可表示第k个人做第a[k]个工作。
由于同一个工作不能被两个人做或者说每个人只能做不同的工作,因此若设行排列固定,则a[k]!=a[j],其中从j=1变到=k-1即第k个人只能做1项的工作。
即他在做第a[k]项工作时要保证前面的工作都没做。
开始:For k =1 to 4a[k]=0;end for;k=1;while k>=1while a[k]<=3a[k]=a[k]+1;v=v+c[k][a[k]];for(j=1;j<=k-1;j++)if(a[k]!=a[j])标记合法与部分解;else标记非法解,剪掉部分;If a[k]为合法解then 输出当前指派和当前最小耗费Else if a[k]为部分解then k=k+1{前进}End while;a[k]=0;k=k-1;v=v-c[k][a[k]];{回溯}End while;输出每次求得的耗费,求出最小的即调用min(s[])函数,并将最小耗费cost输出;结束三、调试过程及运行结果调试过程中出现的问题:虽然按照回溯算法所给的模式写完了程序,却不对,经单步调试发现是我的程序结构混乱,部分解和合法解还有非法解之间的条件处理那有问题,因为通过一个循环要保证一个人只能做一项工作,而且要做别人没做过的工作,此条件对于部分解、合法解都要求,而当它不满足时应跳出作另外处理。
实验四回溯算法和分支限界法(精)
实验四回溯算法和分支限界法0-1背包问题一、实验目的:1、掌握0-1背包问题的回溯算法;2、进一步掌握回溯算法。
二、实验内容给定n和物品和一人背包,物品i的重量是wi,其价值为vi,问如何选择装入背包的物品,使得装入背包的物品的总价值最大?三、实验步骤1、代码// HS_ALG.cpp : Defines the entry point for the console application.//#include#includeusing namespace std;// 物体结构体typedef struct{float w; //物品重量float p; //物品价值float v; //背包体积int id; //物品个数}OBJECT;bool cmp(OBJECT a, OBJECT b{ //比较两物品体积return a.v>b.v;}float knapsack_back(OBJECT ob[], float M, int n, bool x[]{ //回溯法int i,k;float w_cur, p_total, p_cur, w_est, p_est;bool *y = new bool[n+1];// 计算物体的价值重量比for(i=0; i<=n; i++{ob[i].v = ob[i].p/ob[i].w;y[i] = false;}// 按照物体的价值重量比降序排列sort(ob, ob+n, cmp;// 初始化当前背包中的价值、重量w_cur = p_cur = p_total = 0;// 已搜索的可能解的总价值初始化k = 0;while(k>=0{w_est = w_cur; p_est = p_cur;// 沿当前分支可能取得的最大价值for( i=k; iw_est += ob[i].w;if(w_estp_est += ob[i].p;}else{p_est += ((M-w_est+ob[i].w/ob[i].w*ob[i].p; break;}}// 估计值大于上界if(p_est>p_total{for(i=k; iif(w_cur+ob[i].w<=M{// 可装入第i个物体w_cur = w_cur + ob[i].w;p_cur = p_cur + ob[i].p;y[i] = true;}else{// 不能装入第i个物体y[i] = false;break;}}if(i>=n{// n个物体已经全部装入if(p_cur>p_total{// 更新当前上限p_total = p_cur;k = n;// 保存可能的解for(i=0; ix[i] = y[i];}}}else{// 继续装入物体k = i+1;}}else{// 估计值小于上界时while((i>=0&&(!y[i]i--; // 沿着右分支结点方向回溯直到左分支结点if(i<0break; // 到达根结点算法结束else{ // 修改当前值w_cur -= ob[i].w;p_cur -= ob[i].p;y[i] = false;k = i+1; // 搜索右分支子树}}}//delete y;return p_total;}int main({int n;float m;cout<<"请输入背包载重:";cin>>m;cout<<"请输入物品个数:";cin>>n;OBJECT* ob = new OBJECT[n];{cout<<"请输入物品的重量、价格:"< for(int i=0; icin>>ob[i].w>>ob[i].p;ob[i].id = i+1;}}bool* x = new bool[n];float v = knapsack_back(ob, m, n, x; {cout<<"最优方案:"<for(int i=0; iif(x[i]cout<<"["<}cout<cout<<"物品总价值为:"<}return 0;}2、结果执行成功.3、结果分析。
实验四 回溯法
宁德师范学院计算机系
实验报告
(—学年第学期)
课程名称算法设计与分析
实验名称实验四贪心算法
专业
年级
学号姓名
指导教师
实验日期
算法运行结果:
时间复杂性和空间复杂性:
在n皇后问题的可能解中,考虑到约束条件xi不等于xj,则可能解应该是(1,2,3...,n)的一个排列,对应的解空间树中有n!叶子节点,每个叶子节点代表一种可能解。
如果棋盘的长度n=8的话应该是O(n^16),但事实上应该比这快很多,因为O(n^16)会成一个很小的系数,比如第一个顶点要考虑8*8的情况,在确定第二个顶点的时候就是小于7*7的情况了。
空间复杂性为1。
s[St[top].i][St[top].j] = 0; //让该位置变成其它路径可走方块 top--;
}
}
outfile<< "没有可走路径!\n";
}
int main()
{
ifstream infile("input.txt");
if(!infile)
{cerr<<"open file input error!"<<endl;
return -1;
}
int n;
infile>>n; //输入二维数组的行、列数n; MgPath(1,1,n-2,n-2,n);
}
实验结果:
注:1、报告内的项目或设置,可根据实际情况加以补充和调整
2、教师批改学生实验报告应在学生提交实验报告10日内。
回溯与分支限界算法设计
算法设计与分析实验报告1.骑士游历问题(采用回溯法):在国际象棋的棋盘(8行×8列)上放置一个马,按照“马走日字”的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次。
若给定起始位置(x0,y0),编程探索出一条路径,沿着这条路径马能遍历棋盘上的所有单元格。
2. 行列变换问题(采用分支限界法):给定两个m n方格阵列组成的图形A和图形B,每个方格的颜色为黑色或白色,如下图所示。
行列变换问题的每一步变换可以交换任意2行或2列方格的颜色,或者将某行或某列颠倒。
上述每次变换算作一步。
试设计一个算法,计算最少需要多少步,才能将图形A变换为图形B。
图形A图形B2. 行列变换问题的程序:package .t8;import java.util.LinkedList;import java.util.Scanner;class graph{static int sour, dest;//sour是图形的初始整数,dest是图形的目的整数static int ans[]=new int[1<<16];//静态变量(即全局变量),用于存放图形变换的路径int m=4,n=4,x;int row[]=new int[4];int col[]=new int[4];void setx(int x){this.x=x;}int getx(){return this.x;}void rowx(){//将一个整数划分成四行二进制int y;for(int i=0;i<m;i++){y=1;row[i]=0;for(int j=0;j<n;j++){if((x&1)!=0) //如果x的最低位是1row[i]|=y;y<<=1;x>>=1;}}}}实例:总结实验心得体会:掌握回溯法解决问题的一般步骤。
学会使用回溯法解决实际问题。
掌握分支限界法解决问题的基本思想。
回溯算法的实验报告
南华大学计算机科学与技术学院实验报告(2016 ~2017 学年度第二学期)课程名称程序设计语言与编译实验名称回溯算法分析姓名何星佑学号20154340220专业树媒班级 2地点教师罗江琴一、实验目的:通过分析求符号三角形问题的回溯法并编程实现,掌握回溯法的算法框架。
二、实验任务:分析求符号三角形问题的回溯算法,编程实现,调试运行程序并对运行结果进行分析,分析算法的时空复杂度。
三、实验内容:1、实现回溯法求符号三角形问题描述2、算法描述3、程序设计四、实验结果与分析:问题描述:一般情况下,符号三角形的第一行有n个符号,三角形中任意位置都为“+”或“-”,且满足以下两个规则:1)三角形中任意行的下一行的符号由以下规则确定:2个同号下面是“+”,2个异号下面是“-”;2)三角形中“+”或“-”数目相同。
对于给定的n,计算有多少个不同的符号三角形。
问题分析:对于符号三角形问题,用n元组x[1:n]表示符号三角形的第一行的n个符号。
当x[i]=1时,表示符号三角形的第一行的第i个符号为“+”号;当x[i]=0时,表示符号三角形的第一行的第i个符号为“-”号;1 ≤ i≤ 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为奇数时,显然不存在所包含的“+”号个数与“-”号个数相同的符号三角形。
回溯法解背包问题实验报告
实验4回溯法解0-1背包问题一、实验要求1.要求用回溯法求解0-1背包问题;2.要求交互输入背包容量,物品重量数组,物品价值数组;3.要求显示结果。
二、实验仪器和软件平台仪器:带usb接口微机软件平台:WIN-XP + VC++6.0三、实验源码#include "stdafx.h"#include<iostream>#include<cstdio>#include<conio.h>#include<iomanip>using namespace std;template<class ty>class Knap{public:friend void Init();friend void Knapsack();friend void Backtrack(int i);friend float Bound(int i);bool operator<(Knap<ty> a)const{if(fl<a.fl) return true;else return false;}private:ty w; //重量ty v; //价值float fl; //单位重量的价值v/wint kk; //记录第几个物品int flag; //记录是否放入包中};template<class ty>void Sort(Knap<ty> *li,int n){int i,j,k; Knap<ty> minl;for(i=1;i<n;i++){minl=li[0]; k=0;for(j=1;j<=n-i;j++){if(minl<li[j]){minl=li[j]; swap(li[j],li[k]); k=j;}}}}namespace jie //命名空间{int c=0,n=0;int *x=NULL;Knap<int> *bag=NULL;int cp=0,cw=0;int bestp=0;}using namespace jie;void Init(){int i=0;cout<<endl;cout<<"请输入物品数量n = ";cin>>n; cout<<endl;cout<<"请输入背包容量C = ";cin>>c; cout<<endl;bag=new Knap<int> [n];x=new int[n];cout<<"请依次输入"<<n<<"个物品的重量W:"<<endl;for(i=0;i<n;i++)cin>>bag[i].w;cout<<endl;cout<<"请依次输入"<<n<<"个物品的价值P:"<<endl;for(i=0;i<n;i++)cin>>bag[i].v;for(i=0;i<n;i++){bag[i].flag=0; bag[i].kk=i;bag[i].fl=1.0*bag[i].v/bag[i].w;}}void Backtrack(int i){if(i>=n) //到达叶节点{bestp=cp; //更新最优价值return;}if(cw+bag[i].w<=c) //进入左子树{bag[i].flag=1; cw+=bag[i].w;cp+=bag[i].v; Backtrack(i+1);cw-=bag[i].w; cp-=bag[i].v;}if(Bound(i+1)>bestp)//进入右子树{bag[i].flag=0; Backtrack(i+1);}}//计算当前节点处的上界float Bound(int i){int cleft = c-cw; //剩余容量float b = cp;while (i<n&&bag[i].w<=cleft){//以物品单位重量价值递减序装入cleft-=bag[i].w ;b+=bag[i].v;i++;}//装满背包if (i<n) b+=1.0*bag[i].v/bag[i].w * cleft;return b;}void Knapsack() //计算最优解和变量值{int L(0); //用L累计价值,初始价值设置为0for(int k=0;k<n;k++){x[bag[k].kk]=bag[k].flag; //x=0表示未放入背包,x=1表示放入背包L+=bag[k].flag*bag[k].v; //价值累加}cout<<endl;cout<<"当前最优价值为:"<<L<<endl;cout<<"变量值x = ";for(int i=1;i<=n;i++){cout<<x[i-1];}delete []bag; bag=NULL;delete []x; x=NULL;cout<<endl; getch();}int main(){cout<<endl;cout<<"|**********回溯法解0-1背包问题**********|"<<endl;Init();Backtrack(0);Knapsack();return 0;}四、运行结果五、实验小结通过该实验,我充分了解了回溯法与分支界限法的区别。
回溯法实验报告
一、实验目的1. 理解回溯法的概念和基本原理。
2. 掌握回溯法的应用场景和实现方法。
3. 通过具体实例,验证回溯法在解决实际问题中的有效性。
二、实验内容本次实验主要围绕回溯法进行,通过以下实例来验证回溯法在解决实际问题中的有效性:1. 八皇后问题2. 0/1背包问题3. 数独游戏三、实验步骤1. 八皇后问题(1)定义问题:在8×8的国际象棋棋盘上,放置8个皇后,使得它们不能相互攻击。
(2)设计回溯算法:① 初始化棋盘为全空状态。
② 从第一行开始,尝试将皇后放置在每一列。
③ 如果某一列放置皇后后,不会与已放置的皇后发生冲突,则继续在下一行尝试放置。
④ 如果某一列放置皇后后,与已放置的皇后发生冲突,则回溯至上一个放置皇后的行,尝试在下一列放置。
⑤ 当所有行都放置了皇后,则找到一个解。
(3)实现代码:```pythondef is_valid(board, row, col):for i in range(row):if board[i] == col or \board[i] - i == col - row or \board[i] + i == col + row:return Falsereturn Truedef solve_n_queens(board, row):if row == len(board):return Truefor col in range(len(board)):if is_valid(board, row, col):board[row] = colif solve_n_queens(board, row + 1):return Trueboard[row] = -1return Falsedef print_board(board):for row in board:print(' '.join(['Q' if x == row else '.' for x in range(len(board))]))def n_queens():board = [-1] 8if solve_n_queens(board, 0):print_board(board)else:print("No solution exists")n_queens()```2. 0/1背包问题(1)定义问题:给定n个物品,每个物品有重量和价值,背包容量为W,求出能够装入背包的物品组合,使得背包内物品的总价值最大。
实验4回溯法
淮海工学院计算机工程学院实验报告书课程名:《算法分析与设计》题目:实验4 回溯算法0/1背包问题班级:学号:姓名:实验4 回溯算法实验目的和要求(1)掌握回溯法的设计思想;(2)掌握解空间树的构造方法,以及在求解过程中如何存储求解路径; (3)考察回溯法求解问题的有效程度。
(4)设计可能解的表示方式,构成解空间树; (5)设计回溯算法完成问题求解;(6)设计测试数据,统计搜索空间的结点数; 实验内容给定n 种物品和一个容量为C 的背包,物品i 的重量是wi ,其价值为vi ,0/1背包问题是如何选择装入背包的物品(物品不可分割),使得装入背包中物品的总价值最大? 实验环境Turbo C 或VC++ 实验学时2学时,必做实验 数据结构与算法递归算法:void Backtracking(int i)非递归算法---迭代算法:void beibao(int i)核心源代码1. 递归:void Backtracking(int i) {if(i>n) {Print(); return; }if(currentWeight+weight[i]<=content) { //将物品i 放入背包,搜索左子树 nowAnswer[i] = 1;currentWeight += weight[i]; nPrice += price[i];Backtracking(i+1); //完成上面的递归,返回到上一结点,物品i 不放入背包,准备递归右子树t++;currentWeight -= weight[i]; nPrice -= price[i];∑=ji k k a}nowAnswer[i] = 0;Backtracking(i+1);t++;}void Print(){if(nPrice>=bestPrice){bestPrice=nPrice;for(int i=1;i<n;++i){bestAnswer[i]=nowAnswer[i];}}}2.迭代:void beibao(int n){int i,k;for (i=1; i<=n; i++) //初始化x[i]=0;k=1;while (k>=1){t++;x[k]=x[k]+1; //第k个物品放入背包if (x[k]<=2 && k==n){ //得到一个解,输出int currentweight=0,nowprice=0;for (i=1; i<=n; i++){if(x[i]==1){currentweight+=w[i];nowprice+=p[i];}}if((currentweight<=content)&&(nowprice>bestprice)) {for(int j=1;j<=n;j++){put[j]=x[j];if(put[j]==2)put[j]=0;}bestprice=nowprice;}}else if (x[k]<=2 && k<n)k=k+1; //放置下一个物品else{x[k]=0; //拿走第k个物品,重置x[k],回溯 k=k-1;}}}实验结果递归法要比迭代法优化。
算法设计与分析实验指导4_回溯法:排兵布阵
《算法设计与分析》实验指导实验四回溯法一、实验目的:1. 理解回溯法的深度优先搜索策略。
2. 掌握用回溯法解题的算法框架。
3. 掌握回溯法的设计策略。
二、实验指导1. 回溯法的总体思想回溯法的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法。
这种方法适用于解一些组合数相当大的问题。
回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。
如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
2. 贪心算法的基本步骤⑴针对所给问题,定义问题的解空间;⑵确定易于搜索的解空间结构;⑶以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
3. 程序参考template<typename Type> //交换两个变量的值void Swap(Type &a,Type &b){Type t=b;b=a;a=t;}template<typename Type> //创建二维数组void TwoDimArray(Type** &p,int r,int c){p=new Type *[r];for(int i=0; i<r; i++)p[i]=new Type[c];for(int i=0;i<r;i++)for(int j=0;j<c;j++)p[i][j]=0;}template<typename Type> //输出一维数组的元素void Print1(Type a[],int n){for(int i=1; i<=n; i++)cout<<a[i]<<' ';cout<<endl;}三、实验内容及要求:1. 排兵布阵问题某游戏中,不同的兵种处在不同的地形上其攻击能力不一样,现有n个不同兵种的角色{1,2,...,n},需安排在某战区n个点上,角色i在j点上的攻击力为A ij。
《回溯法实验》实验报告
实验4、《回溯法实验》一、实验目的1. 掌握回溯算法思想2. 掌握回溯递归原理3. 了解回溯法典型问题二、实验内容1. 编写一个简单的程序,解决8皇后问题。
2. 批处理作业调度问题[问题描述]给定n个作业的集合J=(J1, J2, … , Jn)。
每一个作业Ji都有两项任务需要分别在2台机器上完成。
每一个作业必须先由机器1处理,然后再由机器2处理。
作业Ji需要机器i的处理时间为tji,i=1,2, … ,n; j=1,2。
对于一个确定的作业调度,设Fji是作业i在机器i上完成处理的时间。
则所有作业在机器2上完成处理的时间和成为该作业调度的完成时间和。
批处理作业调度问题要求对于给定的n个作业,制定一个最佳的作业调度方案,使其完成时间和达到最小。
要求输入:1)作业数 2)每个作业完成时间表:作业完成时间机器1 机器2作业1 2 1作业2 3 1作业3 2 3要求输出: 1)最佳完成时间 2)最佳调度方案提示:算法复杂度为O(n!),建议在测试的时候n值不要太大,可以考虑不要超过12。
3. 数字全排列问题任意给出从1到N的N个连续的自然数,求出这N个自然数的各种全排列。
如N=3时,共有以下6种排列方式:123,132,213,231,312,321。
注意:数字不能重复,N由键盘输入(N<=9)。
三、算法思想分析1.八皇后问题是典型的回溯问题,先从空格子起逐行放皇后,如果符合要求即安全则放置,否则返回上一行下一个位置继续,直至最后一行安全放置则为一种放置方式。
2.批处理作业调度的解空间为排列数,不断利用递归函数直至叶节点,剪枝函数为当前用时与最佳用时的比较。
关于时间的计算,每次选择作业后先将机器1用时累加,机器2上总用时需要先比较上一个作业完成时间与此时机器1上的总用时,如果机器1上总用时大于上一作业用时,那么机器2上用时则加上机器1上用时与此作业在机器2上的单独用时,反之,则代表此时机器2仍然在处理上一任务,那么机器2上用时则加上上一作业用时与此作业在机器2上的单独用时。
回溯法实验(图的m着色问题)
算法分析与设计实验报告第六次附加实验cout<<endl;}elsefor(int i=1;i<=m;i++){x[t]=i;if(ok(t)) Backtrack(t+1);//回溯,继续寻找下一层x[t]=0;//回到最初状态,使x[1]继续尝试其他填色的可能解}}测试结果当输入图如下时:结果如下:12435只要输入边即可当输入的图如下时:结果如下:附录:完整代码(回溯法)//图的m着色问题回溯法求解#include<iostream>using namespace std;class Color{friend void mColoring(int,int,int **);private:bool ok(int k);void Backtrack(int t);int n, //图的顶点个数m, //可用颜色数**a, //图的邻接矩阵*x; //当前解long sum; //当前已找到的可m着色的方案数};bool Color::ok(int k) //检查颜色可用性{for(int j=1;j<=n;j++)if((a[k][j]==1)&&(x[j]==x[k])) //两个点之间有约束且颜色相同return false;return true;}void Color::Backtrack(int t){if(t>n) //到达叶子节点{sum++; //可行解+1cout<<"着色: ";for(int i=1;i<=n;i++) //输出可行解方案cout<<x[i]<<" ";cout<<endl;}elsefor(int i=1;i<=m;i++){x[t]=i;if(ok(t)) Backtrack(t+1);//回溯,继续寻找下一层x[t]=0;//回到最初状态,使x[1]继续尝试其他填色的可能解 }}void mColoring(int n,int m,int **a){Color X;//初始化XX.n=n;X.m=m;X.a=a;X.sum=0;int *p=new int[n+1];for(int i=0;i<=n;i++)p[i]=0;X.x=p;cout<<"顶点: ";for(int i=1;i<=n;i++) //用于输出结果cout<<i<<" " ;cout<<endl;X.Backtrack(1); //从顶点1开始回溯delete []p;cout<<"解法个数:"<<X.sum<<endl;}int main(){int n;int m;cout<<"please input number of node:";cin>>n;cout<<"please input number of color:";cin>>m;int **a=new int*[n+1];for(int i=0;i<=n;i++)a[i]=new int[n+1];for(int i=0;i<=n;i++) //利用抽象图实现图的邻接矩阵for(int j=0;j<=n;j++)a[i][j]=0;int edge;cout<<"please input adjacent edge number:";cin>>edge;int v,w;cout<<"please inout adjacent edge:"<<endl; //只要输入边即可for(int i=0;i<edge;i++){cin>>v>>w; //由于是无向图,所以对应的邻接矩阵对应的边都有,即v->m,m->v都有边a[v][w]=1;a[w][v]=1;}mColoring(n,m,a);system("pause");return 0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验4. 回溯法一、 实验目的1. 理解回溯法的基本思想。
2. 运用回溯法解决实际问题。
二、 实验环境与地点1. 实验环境:Windows7,Eclipse2. 实验地点:网络工程实验室三、 实验内容与步骤编写程序完成下列题目,上机调试并运行成功。
1. 有n 个集装箱要装上2艘载重分别为c1和c2 的轮船,其中集装箱 i 的重量为 w i ,且装载问题要求确定是否有一个合理的装载方案可将这些集装箱装上这 2 艘轮船。
如果有,找出一种装载方案。
思路:可以证明,如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案。
(1)首先将第一艘轮船尽可能装满;(2)将剩余的集装箱装上第二艘轮船。
将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近c1。
由此可知,装载问题等价于以下特殊的0-1背包问题。
输入: w = [10,40,40]c1 = c2 = 50;输出:1,2装第一艘船,其余第2艘船。
令第一艘船的装入量为W1,用回溯算法求使得c1−W1达到最小的装载方案;若满足w1+w2+...+wn−W1≤ c2,则回答“Yes ”,否则回答“No ”步骤:(1) 解空间:子集树可行性约束函数(选择当前元素):211c c wn i i +≤∑=界限函数(不选择当前元素):当前载重量cw+剩余集装箱的重量r <=当前最优载重量bestw(2) 算法:public class Loading {// 类数据成员static int n ;// 集装箱数static int [] w ; // 集装箱重量数组static int c ;// 第一艘轮船的载重量static int cw ; // 当前载重量static int bestw ;// 当前最优载重量static int r ;// 剩余集装箱重量static int [] x ; // 当前解static int [] bestx ; // 当前最优解public static int maxLoading(int [] ww , int cc , int [] xx ) {// 初始化类数据成员n = ww .length - 1;w = ww ;c = cc ;cw = 0;bestw = 0;x = new int [n + 1];bestx = xx ;// 初始化rfor (int i = 1; i <= n ; i ++)r += w [i ];// 计算最优载重量backtrack (1);return bestw ;}// 回溯算法private static void backtrack(int i ) {// 搜索第i 层结点if (i > n ) {// 到达叶结点if (cw > bestw ) {for (int j = 1; j <= n ; j ++)bestx [j ] = x [j ];bestw = cw ;}return ;}11c x w n i i i≤∑=// 搜索子树r -= w [i ];if (cw + w [i ] <= c ) {// 搜索左子树x [i ] = 1;cw += w [i ];backtrack (i + 1);cw -= w [i ];}if (cw + r > bestw ) {x [i ] = 0;// 搜索右子树backtrack (i + 1);}r += w [i ];} public static void main(String[] args ) {// TODO Auto-generated method stub//自己编写代码完成main 方法……}}(3) 测试:输入: W = < 90,80,40,30,20,12,10 >c1=152, c2=130输出:1,3,6,7装第一艘船,其余第2艘船。
2. 批处理作业调度:给定n 个作业的集合{J 1,J 2,…,J n }。
每个作业必须由两台机器处理,且先由机器1处理,再由机器2处理。
作业J i 需要机器j 的处理时间为t ji 。
F ji 是作业i 在机器j 上完成处理的时间。
所有作业在机器2上完成时间和: 批处理作业调度问题要求对于给定的 n 个作业,制定最佳作业调度方案,使其完成时间总和达到最短。
思路:由于每个作业都要处理,只是每个作业在机器上的处理顺序不同,因此,流水作业调度问题的一个候选解是n 个作业的一个排列。
解空间能够组织成一棵排列树。
解空间的大小为n!。
如果在搜索过程中不考虑任何剪支函数,效率低。
但是,该问题里没有显式的约束函数,因此,我们可考虑界限函数。
n i i f F ==∑21这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。
对于当前要加工的作业x[j],在机器1上处理后,记录其结束时间f1,机器2能够接着处理作业x[j],取决于当前机器2是否空闲:如果机器1上处理作业x[j]后,前一个作业在机器2上还没有处理完,作业x[j]只能等待机器2。
同样,如果机器2早就结束了对前一个作业的处理,而机器1仍然还在处理当前作业x[j],因此,机器2必须等待机器1完成处理作业x[j]后,才能处理x[j]。
因此,我们必须比较机器2完成前一个作业的完成时间f2[i-1]与f1的大小,然后才能决定机器2从什么时候开始处理x[j]。
步骤:(1)解空间树——排列树(2)算法import java.util.Arrays;public class FlowShop {static int[][] m= {{0,0,0,},{0,2,1,},{0,3,1,},{0,2,3,}}; // 各作业所需的处理时间static int[] x=new int[m.length];// 当前作业调度static int[] bestx=new int[x.length];// 当前最优作业调度static int[] f2=new int[x.length]; // 机器2完成处理时间static int n=x.length-1, // 作业数f1=0, // 机器1完成处理时间f=0, // 完成时间和bestf=99999; // 当前最优值private static void backtrack(int i) {if (i > n) {//得到一个当前最优解for (int j = 1; j <= n; j++)bestx[j] = x[j];bestf = f;//bestf的初值为一最大值99999} elsefor (int j = i; j <= n; j++) {f1 += m[x[j]][1];//第i个被调度的作业j在机器1的完成处理的时间//第i个被调度作业j在机器2上完成处理的时间f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + m[x[j]][2];//前i个被调度作业在机器2上完成处理的时间和f += f2[i];if (f < bestf) {//限界条件MyMath.swap(x, i, j);//将作业j换到最前作为排列前缀backtrack(i + 1);MyMath.swap(x, i, j);//回溯后,将作业j换回原来位置}f1 -= m[x[j]][1];//回溯到第i-1层,恢复前i-1个作业在机器1上的完成处理时间f -= f2[i];//回溯到第i-1层,恢复前i-1个作业在机器2上的完成处理时间和}}public static void main(String[] args) {// TODO Auto-generated method stub//自己编写代码完成main方法……}}四、实验总结与分析此处要包含前面算法的时间复杂度分析。
参考代码:(1)Loading:import java.util.Arrays;public class Loading {// 类数据成员static int n;// 集装箱数static int[] w; // 集装箱重量数组static int c;// 第一艘轮船的载重量static int cw; // 当前载重量static int bestw;// 当前最优载重量static int r;// 剩余集装箱重量static int[] x; // 当前解static int[] bestx; // 当前最优解public static int maxLoading(int[] ww, int cc, int[] xx) { // 初始化类数据成员n = ww.length - 1;w = ww;c = cc;cw = 0;bestw = 0;x = new int[n + 1];bestx = xx;// 初始化rfor (int i = 1; i <= n; i++)r += w[i];// 计算最优载重量backtrack(1);return bestw;}// 回溯算法private static void backtrack(int i) {// 搜索第i层结点if (i > n) {// 到达叶结点if (cw > bestw) {for (int j = 1; j <= n; j++)bestx[j] = x[j];bestw = cw;}return;}// 搜索子树r -= w[i];if (cw + w[i] <= c) {// 搜索左子树x[i] = 1;cw += w[i];backtrack(i + 1);cw -= w[i];}if (cw + r > bestw) {x[i] = 0;// 搜索右子树backtrack(i + 1);}r += w[i];}public static void main(String[] args) {// TODO Auto-generated method stubint[] ww= {0,10,40,40, };//0,90,80,40,30,20,12,10 int c1=50;int c2=50;int cc2=0;int[] xx= new int[ww.length];maxLoading(ww,c1,xx);for (int i = 1; i < xx.length; i++) {if (xx[i]==0) {cc2+=ww[i];}}if (cc2<=c2) {System.out.println("yes");System.out.println(bestw);System.out.println(Arrays.toString(bestx));}else {System.out.println("no");}}}(2)FlowShopimport java.util.Arrays;public class FlowShop {static int[][] m= {{0,0,0,},{0,2,1,},{0,3,1,},{0,2,3,}}; // 各作业所需的处理时间static int[] x=new int[m.length];// 当前作业调度static int[] bestx=new int[x.length];// 当前最优作业调度static int[] f2=new int[x.length]; // 机器2完成处理时间static int n=x.length-1, // 作业数f1=0, // 机器1完成处理时间f=0, // 完成时间和bestf=99999; // 当前最优值private static void backtrack(int i) {if (i > n) {//得到一个当前最优解for (int j = 1; j <= n; j++)bestx[j] = x[j];bestf = f;//bestf的初值为一最大值99999} elsefor (int j = i; j <= n; j++) {f1 += m[x[j]][1];//第i个被调度的作业j在机器1的完成处理的时间//第i个被调度作业j在机器2上完成处理的时间f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + m[x[j]][2];//前i个被调度作业在机器2上完成处理的时间和f += f2[i];if (f < bestf) {//限界条件MyMath.swap(x, i, j);//将作业j换到最前作为排列前缀backtrack(i + 1);MyMath.swap(x, i, j);//回溯后,将作业j换回原来位置}f1 -= m[x[j]][1];//回溯到第i-1层,恢复前i-1个作业在机器1上的完成处理时间f -= f2[i];//回溯到第i-1层,恢复前i-1个作业在机器2上的完成处理时间和}}public static void main(String[] args) {// TODO Auto-generated method stubfor (int i = 1; i < x.length; i++) {x[i]=i;}backtrack(1);System.out.println(bestf);System.out.println(Arrays.toString(bestx));}}public class MyMath {public static void swap(int[] data, int a, int b) {int temp;temp = data[a];data[a] = data[b];data[b] = temp;}}。