程序设计算法实验指导 回溯Word文档下载推荐.docx
《程序设计算法实验指导 回溯Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《程序设计算法实验指导 回溯Word文档下载推荐.docx(11页珍藏版)》请在冰豆网上搜索。
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++)
(%d,%d)"
i,x[i]);
\n"
);
else
x[t]=i;
if(Place(t,x))Backtrack(t+1,n,x);
/*如果新加入第t个皇后所在的位置i没有与其他皇后的位置冲突,则进入解空间子树,试探第t+1个皇后的位置;
否则不进入子树,舍弃该段子树,即进行剪枝*/
main()
intn,*x;
请输入皇后的个数:
scanf("
%d"
&
n);
x=(int*)malloc((n+1)*sizeof(int));
/*x[0]未使用*/
以下每个方案都表示出了%d个皇后在棋盘上的坐标\n\n"
n);
Backtrack(1,n,x);
/*求解*/
总共有%d种方案\n"
}
2.桥本分数式(具体题目见书P34),并输出解的个数。
回溯实现:
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]<
a[4])
{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++;
(-)"
s);
%d/%ld+%d/"
a[1],m1,a[4]);
%ld=%d/%ld"
m2,a[7],m3);
if(s%2==0)printf("
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结束
共以上%d个解。
递归程序实现:
//桥本分数式递归求解
inta[10],s=0;
{intput(intk);
put
(1);
//调用递归函数put
(1)
共有以上%d个解。
//桥本分数式递归函数
intput(intk)
{inti,j,u,m1,m2,m3;
if(k<
=9)
{for(i=1;
=9;
i++)//探索第k个数字取值i
{a[k]=i;
for(u=0,j=1;
=k-1;
j++)
if(a[k]==a[j])
u=1;
//出现重复数字,则置u=1
if(u==0)//若第k个数字可为i
{if(k==9&
a[4])//若已9个数字,则检查等式
{m1=a[2]*10+a[3];
if(a[1]*m2*m3+a[4]*m1*m3==a[7]*m1*m2)
{s++;
printf("
<
->
:
"
//输出一个解
%d/%d+%d/%d"
a[1],m1,a[4],m2);
=%d/%d"
a[7],m3);
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}
conio.h>
#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;
Pleaseinputthenumberofthenumbers:
scanf("
Pleaseinputthesum:
c);
for(i=1;
i++)
scanf("
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)
if(c_sum+num[i]>
c)
return;
for(intj=i;
result[count++]=num[j];
c_sum+=num[j];
swap(num[i],num[j]);
back_subset(i+1);
c_sum-=num[j];
count--;
b)
inttemp=a;
a=b;
b=temp;
iostream>
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:
endl;
cin>
>
sum;
ints=0,k=0,r;
r=Sum();
//cout<
r<
endl;
SumOfSub(s,k,r);
intSum()
ints=0;
for(inti=0;
i<
MAX;
s+=b[i];
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]<
//{
x[k]=0;
SumOfSub(s,k+1,r-b[k]);
//}
voidDisplay(int*x)
if(x[i]==1)
cout<
b[i]<
\t"
;
这个算法应该不难,基本和全排列的算法类似,只不过判断条件不是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;