程序设计算法实验指导 回溯.docx

上传人:b****7 文档编号:8899239 上传时间:2023-02-02 格式:DOCX 页数:11 大小:99.46KB
下载 相关 举报
程序设计算法实验指导 回溯.docx_第1页
第1页 / 共11页
程序设计算法实验指导 回溯.docx_第2页
第2页 / 共11页
程序设计算法实验指导 回溯.docx_第3页
第3页 / 共11页
程序设计算法实验指导 回溯.docx_第4页
第4页 / 共11页
程序设计算法实验指导 回溯.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

程序设计算法实验指导 回溯.docx

《程序设计算法实验指导 回溯.docx》由会员分享,可在线阅读,更多相关《程序设计算法实验指导 回溯.docx(11页珍藏版)》请在冰豆网上搜索。

程序设计算法实验指导 回溯.docx

程序设计算法实验指导回溯

程序设计算法实验二——回溯算法(黑体,三号)

1.回溯简介(小标题:

黑体,小四;内容:

宋体,五号)

回溯法找出求解问题的线索往前试探,若试探成功,即得到解;若试探失败,就逐步往回退,换其他路线再往前试探。

2.算法流程或设计思想

3.分析算法的时间复杂度

4.程序设计中的问题及解决方案

5.运行说明(包括实验数据和结果说明)

6.主要程序代码(添加程序注释)

7.对比解决该问题的其他算法(选作)

题目:

1.8-皇后问题:

在国际象棋盘上放八个皇后,要求任一皇后吃不到别人,也不受其他皇后的攻击,求出问题的所有解。

参考答案:

#include

#include

#include

intsum=0;/*记录方案的个数*/

intPlace(intk,int*x)

/*判断新加入的皇后所在的位置k是否与其他皇后的位置冲突,此函数用来作为是否进行剪枝的判断条件*/

{

intj;

for(j=1;j

if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))/*x[i]表示皇后i放在棋盘的第i行的第x[i]列*/

return0;/*能攻击到其他皇后,返回0*/

return1;/*不能攻击到其他皇后,返回1*/

}

voidBacktrack(intt,intn,int*x)

/*递归回溯求解*/

{

inti;

if(t>n)

{

sum++;

/*输出一个方案*/

printf("方案%d:

",sum);

for(i=1;i<=n;i++)

printf("(%d,%d)",i,x[i]);

printf("\n");

}

else

for(i=1;i<=n;i++)

{

x[t]=i;

if(Place(t,x))Backtrack(t+1,n,x);/*如果新加入第t个皇后所在的位置i没有与其他皇后的位置冲突,则进入解空间子树,试探第t+1个皇后的位置;否则不进入子树,舍弃该段子树,即进行剪枝*/

}

}

main()

{

intn,*x;

inti;

printf("请输入皇后的个数:

");

scanf("%d",&n);

x=(int*)malloc((n+1)*sizeof(int));/*x[0]未使用*/

printf("以下每个方案都表示出了%d个皇后在棋盘上的坐标\n\n",n);

Backtrack(1,n,x);/*求解*/

printf("总共有%d种方案\n",sum);

}

2.桥本分数式(具体题目见书P34),并输出解的个数。

回溯实现:

#include

voidmain()

{intg,i,k,s,a[10];

longm1,m2,m3;

i=1;a[1]=1;s=0;

while

(1)

{g=1;

for(k=i-1;k>=1;k--)

if(a[i]==a[k]){g=0;break;}//两数相同,标记g=0

if(i==9&&g==1&&a[1]

{m1=a[2]*10+a[3];

m2=a[5]*10+a[6];

m3=a[8]*10+a[9];

if(a[1]*m2*m3+a[4]*m1*m3==a[7]*m1*m2)//判断等式

{s++;printf("(-)",s);

printf("%d/%ld+%d/",a[1],m1,a[4]);

printf("%ld=%d/%ld",m2,a[7],m3);

if(s%2==0)printf("\n");

}

}

if(i<9&&g==1)

{i++;a[i]=1;continue;}//不到9个数,往后继续

while(a[i]==9&&i>1)i--;//往前回溯

if(a[i]==9&&i==1)break;

elsea[i]++;//至第1个数为9结束

}

printf("共以上%d个解。

\n",s);

}

递归程序实现:

//桥本分数式递归求解

#include

inta[10],s=0;

voidmain()

{intput(intk);

put

(1);//调用递归函数put

(1)

printf("共有以上%d个解。

\n",s);

}

//桥本分数式递归函数

#include

intput(intk)

{inti,j,u,m1,m2,m3;

if(k<=9)

{for(i=1;i<=9;i++)//探索第k个数字取值i

{a[k]=i;

for(u=0,j=1;j<=k-1;j++)

if(a[k]==a[j])

u=1;//出现重复数字,则置u=1

if(u==0)//若第k个数字可为i

{if(k==9&&a[1]

{m1=a[2]*10+a[3];m2=a[5]*10+a[6];

m3=a[8]*10+a[9];

if(a[1]*m2*m3+a[4]*m1*m3==a[7]*m1*m2)

{s++;printf("<->:

",s);//输出一个解

printf("%d/%d+%d/%d",a[1],m1,a[4],m2);

printf("=%d/%d",a[7],m3);

if(s%2==0)printf("\n");

}

}

elseput(k+1);//若不到9个数字,则调用put(k+1)

}

}

}

returns;

}

3.给定有n个不同的正数组成的集合W={Wi|Wi>0,i=1,2,…,n}和给定正数M,求出M中所有使其和数等于M的子集。

即给定一个n个整数的集合W={W1,W2....Wn}和整数M,找出和等于M的W的子集。

如:

W={11,13,24,7}M=31问题的解为:

{24,7}和{11,13,7}

解可以用布尔向量表示为:

{0,0,1,1},{1,1,0,1}

又如:

W={10,20,30,40,50,60}和M=60,则有三种不同长度的解,它们分别是{10,20,30},{20,40},{60}.这个问题可以用另一种方法明确表达,使得解是一种明显的长度为n的布尔向量,于是上面的三个解可以用布尔向量表示为:

{1,1,1,0,0,0},{0,1,0,1,0,0},{0,0,0,0,0,1}

 

#include

#include

#defineMAX1000

//globalvariables

intn=0;//thenumberofnumbers

intc=0;//thesumofthesubset

intnum[MAX]={0};

intcount=1;//thenumberoftheelementinasubset

intresult[MAX]={0};//theanswerofthisquestion

intc_sum=0;//currentsum

//prototypes

voidswap(int&a,int&b);

voidback_subset(inti);

intmain()

{

//declaration

inti=0;

printf("Pleaseinputthenumberofthenumbers:

");

scanf("%d",&n);

printf("Pleaseinputthesum:

");

scanf("%d",&c);

for(i=1;i<=n;i++)

scanf("%d",&num[i]);

back_subset

(1);

getch();

}

voidback_subset(inti)

{

if(c_sum+num[i]==c)

{

result[count]=num[i];

for(inttemp=1;temp<=count;temp++)

printf("%d",result[temp]);

printf("\n\n\n\n----------separateline------------------\n\n\n\n");

return;

}

if(i>n)

return;

if(c_sum+num[i]>c)

return;

for(intj=i;j<=n;j++)

{

result[count++]=num[j];

c_sum+=num[j];

swap(num[i],num[j]);

back_subset(i+1);

swap(num[i],num[j]);

c_sum-=num[j];

count--;

}

}

voidswap(int&a,int&b)

{

inttemp=a;

a=b;

b=temp;

}

 

#include

usingnamespacestd;

constintMAX=11;

constintb[MAX]={1,2,3,4,5,8,11,23,45};

intx[MAX]={0};

intsum;

intSum();

intSumOfSub(int,int,int);

voidDisplay(int*);

intmain()

{

cout<<"enterthesum:

"<

cin>>sum;

ints=0,k=0,r;

r=Sum();

//cout<

SumOfSub(s,k,r);

return0;

}

intSum()

{

ints=0;

for(inti=0;i

{

s+=b[i];

}

returns;

}

intSumOfSub(ints,intk,intr)

{

if(r<0)return0;

x[k]=1;

if(s+b[k]==sum)

{

Display(x);

}

if(s+b[k]+b[k+1]<=sum)

SumOfSub(s+b[k],k+1,r-b[k]);

//if(s+r-b[k]>=sum&&s+b[k+1]<=sum)

//{

x[k]=0;

SumOfSub(s,k+1,r-b[k]);

//}

return0;

}

voidDisplay(int*x)

{

for(inti=0;i

{

if(x[i]==1)

cout<

}

cout<

}

这个算法应该不难,基本和全排列的算法类似,只不过判断条件不是n=1,而是在判断已经取得的数的和>=M为终止条件。

具体的算法,我给个大概流程吧

intlst[N];//保存选取的数

intindex=0;//lst中最后的一个数的位置

func(W,N)

{

if(N==0)//遍历完毕返回

return;

for(i=0toN)

{

if(W[i][1]!

=-1)//判断是否已经读取当前值

{

lst[index++]=W[i][0]//当前值加入到保存数组

W[i][1]=-1;//设置当前值已经读取,不可再读

if(check()==0)

{

func(W,N-1);//大小不够M,继续往下读

}

elseif(check()==1)

{

print(lst);//和为M,输出

}

lst[--index]=0;//回溯,寻找下一组解

W[i][1]=0;

}

}

}

check()

{

if(sum(lst)>W)

return-1;

if(sum(lst)

return0;

return1;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 动态背景

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1