实验四 回溯算法和分支限界法Word格式.docx
《实验四 回溯算法和分支限界法Word格式.docx》由会员分享,可在线阅读,更多相关《实验四 回溯算法和分支限界法Word格式.docx(19页珍藏版)》请在冰豆网上搜索。
个三角形:
endl;
for(inti=1;
i<
=n;
i++)
for(intj=1;
j<
i;
j++)
"
;
}
for(j=1;
=n-i+1;
ch[p[i][j]]<
else
for(inti=0;
=1;
p[1][t]=i;
//确定第一行第t个的值;
count+=i;
//用来计算‘-’的个数;
for(intj=2;
=t;
p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2];
//对于第一行大于等于2时确定后面从第2行开始增加的一
count+=p[j][t-j+1];
//列中符号,计算‘-’个数;
if(count<
=half&
&
(t*(t+1)/2-count)<
=half)//约束条件;
BackTrace(t+1);
for(j=2;
j++)//回溯,判断另一种符号情况;
count-=p[j][t-j+1];
count-=p[1][t];
}
voidmain()
请输入第一行符号的个数:
cin>
>
n;
count=0;
sum=0;
half=n*(n+1)/2;
if(half%2==0)
half=half/2;
p=newuchar*[n+1];
p[i]=newuchar[n+1];
memset(p[i],0,sizeof(uchar)*(n+1));
BackTrace
(1);
for(i=0;
delete[]p[i];
delete[]p;
满足要求的三角形符号共有:
个"
不存在这样的三角形符号!
运行结果:
分析:
计算可行性约束需要O(n)时间,在最坏情况下有O(2^n)个结点需要计算可行性约束,故解符号三角形问题的回溯算法所需的计算时间为O(n2^n)。
基本题二:
0—1背包问题
1、掌握0—1背包问题的回溯算法;
2、进一步掌握回溯算法;
二、实验题:
给定n种物品和一背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
#include<
stdio.h>
intn,c,bestp;
//物品的个数,背包的容量,最大价值
intp[10000],w[10000],x[10000],bestx[10000];
//物品的价值,物品的重量,x[i]暂存物品的选中情况,物品的选中情况
voidBacktrack(inti,intcp,intcw)
{//cw当前包内物品重量,cp当前包内物品价值
intj;
if(i>
n)//回溯结束
if(cp>
bestp)
bestp=cp;
for(i=0;
i++)bestx[i]=x[i];
else
for(j=0;
j++)
x[i]=j;
if(cw+x[i]*w[i]<
=c)
cw+=w[i]*x[i];
cp+=p[i]*x[i];
Backtrack(i+1,cp,cw);
cw-=w[i]*x[i];
cp-=p[i]*x[i];
intmain()
inti;
bestp=0;
printf("
请输入背包最大容量:
\n"
);
scanf("
%d"
&
c);
请输入物品个数:
n);
请依次输入物品的重量:
for(i=1;
i++)
w[i]);
请依次输入物品的价值:
p[i]);
Backtrack(1,0,0);
最大价值为:
%d\n"
bestp);
被选中的物品依次是(0表示未选中,1表示选中)\n"
%d"
bestx[i]);
return0;
计算上界需要O(n)时间,在最坏情况下有O(2^n)个右儿子节点需要计算上界,故解0-1背包问题的回溯算法所需要的计算时间为O(n2^n)。
提高题一:
旅行商售货员问题的分支限界算法
1、掌握旅行商售货员问题的分支限界算法;
2、区分分支限界算法与回溯算法的区别,加深对分支限界法的理解。
某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。
他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。
istream>
//---------------------宏定义------------------------------------------
#defineMAX_CITY_NUMBER10//城市最大数目
#defineMAX_COST10000000//两个城市之间费用的最大值
//---------------------全局变量----------------------------------------
intCity_Graph[MAX_CITY_NUMBER][MAX_CITY_NUMBER];
//表示城市间边权重的数组
intCity_Size;
//表示实际输入的城市数目
intBest_Cost;
//最小费用
intBest_Cost_Path[MAX_CITY_NUMBER];
//最小费用时的路径
//------------------------定义结点---------------------------------------
typedefstructNode{
intlcost;
//优先级
intcc;
//当前费用
intrcost;
//剩余所有结点的最小出边费用的和
ints;
//当前结点的深度,也就是它在解数组中的索引位置
intx[MAX_CITY_NUMBER];
//当前结点对应的路径
structNode*pNext;
//指向下一个结点
}Node;
//---------------------定义堆和相关对操作--------------------------------
typedefstructMiniHeap{
Node*pHead;
//堆的头
}MiniHeap;
//初始化
voidInitMiniHeap(MiniHeap*pMiniHeap){
pMiniHeap->
pHead=newNode;
pHead->
pNext=NULL;
}
//入堆
voidput(MiniHeap*pMiniHeap,Nodenode){
Node*next;
Node*pre;
Node*pinnode=newNode;
//将传进来的结点信息copy一份保存
//这样在函数外部对node的修改就不会影响到堆了
pinnode->
cc=node.cc;
lcost=node.lcost;
pNext=node.pNext;
rcost=node.rcost;
s=node.s;
for(intk=0;
k<
City_Size;
k++){
x[k]=node.x[k];
}
pre=pMiniHeap->
pHead;
next=pMiniHeap->
pNext;
if(next==NULL){
pNext=pinnode;
else{
while(next!
=NULL){
if((next->
lcost)>
(pinnode->
lcost)){//发现一个优先级大的,则置于其前面
pNext=pre->
pre->
break;
//跳出
pre=next;
next=next->
//放在末尾
//出堆
Node*RemoveMiniHeap(MiniHeap*pMiniHeap){
Node*pnode=NULL;
if(pMiniHeap->
pNext!
pnode=pMiniHeap->
pNext=pMiniHeap->
pNext->
returnpnode;
//---------------------分支限界法找最优解--------------------------------
voidTraveler(){
inti,j;
inttemp_x[MAX_CITY_NUMBER];
Node*pNode=NULL;
intminiSum;
//所有结点最小出边的费用和
intminiOut[MAX_CITY_NUMBER];
//保存每个结点的最小出边的索引
MiniHeap*heap=newMiniHeap;
//分配堆
InitMiniHeap(heap);
//初始化堆
miniSum=0;
i++){
miniOut[i]=MAX_COST;
//初始化时每一个结点都不可达
j++){
if(City_Graph[i][j]>
0&
City_Graph[i][j]<
miniOut[i]){
//从i到j可达,且更小
miniOut[i]=City_Graph[i][j];
if(miniOut[i]==MAX_COST){//i城市没有出边
Best_Cost=-1;
return;
miniSum+=miniOut[i];
i++){//初始化的最优路径就是把所有结点依次走一遍
Best_Cost_Path[i]=i;
Best_Cost=MAX_COST;
//初始化的最优费用是一个很大的数
pNode=newNode;
//初始化第一个结点并入堆
pNode->
lcost=0;
//当前结点的优先权为0也就是最优
cc=0;
//当前费用为0(还没有开始旅行)
rcost=miniSum;
//剩余所有结点的最小出边费用和就是初始化的miniSum
s=0;
//层次为0
x[k]=Best_Cost_Path[k];
//第一个结点所保存的路径也就是初始化的路径
put(heap,*pNode);
//入堆
while(pNode!
=NULL&
(pNode->
s)<
City_Size-1){
//堆不空不是叶子
Best_Cost_Path[k]=pNode->
x[k];
//将最优路径置换为当前结点本身所保存的
/*
**pNode结点保存的路径中的含有这条路径上所有结点的索引
**x路径中保存的这一层结点的编号就是x[City_Size-2]
**下一层结点的编号就是x[City_Size-1]
*/
if((pNode->
s)==City_Size-2){//是叶子的父亲
intedge1=City_Graph[(pNode->
x)[City_Size-2]][(pNode->
x)[City_Size-1]];
intedge2=City_Graph[(pNode->
x)[City_Size-1]][(pNode->
x)[0]];
if(edge1>
=0&
edge2>
cc+edge1+edge2)<
Best_Cost){
//edge1-1表示不可达
//叶子可达起点费用更低
Best_Cost=pNode->
cc+edge1+edge2;
cc=Best_Cost;
lcost=Best_Cost;
//优先权为Best_Cost
s++;
//到达叶子层
else{//内部结点
for(i=pNode->
s;
i++){//从当前层到叶子层
if(City_Graph[pNode->
x[pNode->
s]][pNode->
x[i]]>
=0){//可达
//pNode的层数就是它在最优路径中的位置
inttemp_cc=pNode->
cc+City_Graph[pNode->
x[i]];
inttemp_rcost=pNode->
rcost-miniOut[pNode->
s]];
//下一个结点的剩余最小出边费用和
//等于当前结点的rcost减去当前这个结点的最小出边费用
if(temp_cc+temp_rcost<
Best_Cost){//下一个结点的最小出边费用和小于当前的最优解,说明可能存在更优解
for(j=0;
j++){//完全copy路径,以便下面修改
temp_x[j]=Best_Cost_Path[j];
temp_x[pNode->
s+1]]=Best_Cost_Path[i];
//将当前结点的编号放入路径的深度为s+1的地方
temp_x[i]=Best_Cost_Path[pNode->
s+1];
//将原路//径中的深度为s+1的结点编号放入当前路径的
//相当于将原路径中的的深度为i的结点与深度W为s+1的结点交换
Node*pNextNode=newNode;
pNextNode->
cc=temp_cc;
lcost=temp_cc+temp_rcost;
rcost=temp_rcost;
s=pNode->
s+1;
x[k]=temp_x[k];
put(heap,*pNextNode);
deletepNextNode;
pNode=RemoveMiniHeap(heap);
intmain(){
请输入旅行的节点数"
City_Size);
请分别输入每个节点与其它节点的路程花费"
City_Graph[i][j]);
Traveler();
最小花费"
Best_Cost);
return1;
提高题二:
用回溯法求解跳马问题
一、实验要求与目的
1、掌握回溯法的基本原理。
2、使用回溯法编程,求解跳马问题
二、实验内容
1、问题描述:
在N*N棋盘上有N2个格子,马在初始位置(X0,Y0),按照象棋中马走“日”的规则,使马走遍全部格子且每个格子仅经过一次。
编程输出马的走法。
2、给出算法描述。
编程实现,给出N=5,(X0,Y0)=(1,1)时的运行结果。
classTiaoma
public:
intN;
intx;
inty;
intA;
intCount;
intMap[6][6];
Tiaoma(intn,intx,inty):
N(n),x(x),y(y){A=1;
Count=1;
voidHorse(intx,inty);
voidPrint();
voidRoud();
voidTiaoma:
:
Horse(intx,inty)
if(1<
=x-2&
y+1<
=N&
Map[x-2][y+1]==0)
Map[x-2][y+1]=++A;
Count++;
Horse(x-2,y+1);
=x-1&
y+2<
Map[x-1][y+2]==0)
Map[x-1][y+2]=++A;
Horse(x-1,y+2);
if(x+1<
Map[x+1][y+2]==0)
Map[x+1][y+2]=++A;
Horse(x+1,y+2);
if(x+2<
Map[x+2][y+1]==0)
Map[x+2][y+1]=++A;
Horse(x+2,y+1);
1<
=y-1&
Map[x+2][y-1]==0)
Map[x+2][y-1]=++A;
Horse(x+2,y-1);
=y-2&
Map[x+1][y-2]==0)
Map[x+1][y-2]=++A;
Horse(x+1,y-2);
Map[x-1][y-2]==0)
Map[x-1][y-2]=++A;
Horse(x-1,y-2);
Map[x-2][y-1]==0)
Map[x-2][y-1]=++A;
Horse(x-2,y-1);
Print()
'
\t'
for(inti1=1;
i1<
=N;
i1++)
列"
for(inti=1;
行"
for(intj=1;
Map[i][j]<
Roud()
跳马路线为:
ints=1;
for(;
s<
=Count;
)
for(intl=1;
l<
l++)
for(intk=1;
k++)
if(Map[l][k]==s&
Count)
Map["
]["
]"
->
if(s%7==0)
s++;
elseif(Map[l][k]==s&
s==C