程序设计算法实验指导 回溯.docx
《程序设计算法实验指导 回溯.docx》由会员分享,可在线阅读,更多相关《程序设计算法实验指导 回溯.docx(11页珍藏版)》请在冰豆网上搜索。
程序设计算法实验指导回溯
程序设计算法实验二——回溯算法(黑体,三号)
1.回溯简介(小标题:
黑体,小四;内容:
宋体,五号)
回溯法找出求解问题的线索往前试探,若试探成功,即得到解;若试探失败,就逐步往回退,换其他路线再往前试探。
2.算法流程或设计思想
3.分析算法的时间复杂度
4.程序设计中的问题及解决方案
5.运行说明(包括实验数据和结果说明)
6.主要程序代码(添加程序注释)
7.对比解决该问题的其他算法(选作)
题目:
1.8-皇后问题:
在国际象棋盘上放八个皇后,要求任一皇后吃不到别人,也不受其他皇后的攻击,求出问题的所有解。
参考答案:
#include
intsum=0;/*记录方案的个数*/
intPlace(intk,int*x)
/*判断新加入的皇后所在的位置k是否与其他皇后的位置冲突,此函数用来作为是否进行剪枝的判断条件*/
{
intj;
for(j=1;jif((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");}elsefor(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),并输出解的个数。回溯实现:#includevoidmain(){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=0if(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);}递归程序实现://桥本分数式递归求解#includeinta[10],s=0;voidmain(){intput(intk);put(1);//调用递归函数put(1)printf("共有以上%d个解。\n",s);}//桥本分数式递归函数#includeintput(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=1if(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//globalvariablesintn=0;//thenumberofnumbersintc=0;//thesumofthesubsetintnum[MAX]={0};intcount=1;//thenumberoftheelementinasubsetintresult[MAX]={0};//theanswerofthisquestionintc_sum=0;//currentsum//prototypesvoidswap(int&a,int&b);voidback_subset(inti);intmain(){//declarationinti=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;} #includeusingnamespacestd;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;}
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
x[t]=i;
if(Place(t,x))Backtrack(t+1,n,x);/*如果新加入第t个皇后所在的位置i没有与其他皇后的位置冲突,则进入解空间子树,试探第t+1个皇后的位置;否则不进入子树,舍弃该段子树,即进行剪枝*/
main()
intn,*x;
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),并输出解的个数。
回溯实现:
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);}递归程序实现://桥本分数式递归求解#includeinta[10],s=0;voidmain(){intput(intk);put(1);//调用递归函数put(1)printf("共有以上%d个解。\n",s);}//桥本分数式递归函数#includeintput(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=1if(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//globalvariablesintn=0;//thenumberofnumbersintc=0;//thesumofthesubsetintnum[MAX]={0};intcount=1;//thenumberoftheelementinasubsetintresult[MAX]={0};//theanswerofthisquestionintc_sum=0;//currentsum//prototypesvoidswap(int&a,int&b);voidback_subset(inti);intmain(){//declarationinti=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;} #includeusingnamespacestd;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;}
{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);
递归程序实现:
//桥本分数式递归求解
inta[10],s=0;
{intput(intk);
put
(1);//调用递归函数put
printf("共有以上%d个解。
//桥本分数式递归函数
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//globalvariablesintn=0;//thenumberofnumbersintc=0;//thesumofthesubsetintnum[MAX]={0};intcount=1;//thenumberoftheelementinasubsetintresult[MAX]={0};//theanswerofthisquestionintc_sum=0;//currentsum//prototypesvoidswap(int&a,int&b);voidback_subset(inti);intmain(){//declarationinti=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;} #includeusingnamespacestd;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;}
{m1=a[2]*10+a[3];m2=a[5]*10+a[6];
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);
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}
#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:
printf("Pleaseinputthesum:
scanf("%d",&c);
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)
if(c_sum+num[i]>c)
for(intj=i;j<=n;j++)
result[count++]=num[j];
c_sum+=num[j];
swap(num[i],num[j]);
back_subset(i+1);
c_sum-=num[j];
count--;
voidswap(int&a,int&b)
inttemp=a;
a=b;
b=temp;
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*);
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;}
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;}
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;}
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]<=sum)
//{
x[k]=0;
SumOfSub(s,k+1,r-b[k]);
//}
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;}
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;}
这个算法应该不难,基本和全排列的算法类似,只不过判断条件不是n=1,而是在判断已经取得的数的和>=M为终止条件。
具体的算法,我给个大概流程吧
intlst[N];//保存选取的数
intindex=0;//lst中最后的一个数的位置
func(W,N)
if(N==0)//遍历完毕返回
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;}
return1;
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1