回溯法——设计一个算法在1、2、3... 9(顺序不能变)数字之间插入+ 或 - 或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性和全排列

回溯法

题目描述:

设计一个算法在1、2、3… 9(顺序不能变)数字之间插入+ 或 - 或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性。例如1+2+34-5+67-8+9=100

分析思路:
用数组a存放1 ~ 9的整数,用字符数组op存放插入的运算符,op[i]表示在a[i]之前插入的运算符。采用回溯法产生和为100的表达式,op[i]只能取+、- 或者空格。

设计函数fun(op,sum,prevadd,a,i)
sum:记录考虑整数a[i]时前面表达式计算的整数和(初始值为a[0])
prevadd:记录前面表达式中的一个数值(初始值为a[0])
i:从1开始到8结束,若sum=100,得到一个解

代码:

#include<stdio.h>
#define N 9
void fun(char op[],int sum,int prevadd,int a[],int i){
    
    
	if(i==N)   //扫描完所有位置
	{
    
    
		if(sum==100)  //找到一个解
		{
    
     printf(" %d",a[0]); //输出解
		for(int j=1;j<N;j++)
		{
    
    
			if(op[j]!=' ')
			printf("%c",op[j]);
			printf("%d",a[j]);
		 } 
		 printf("=100\n");
		 } 
		 return;
	 } 
	 op[i]='+';  //位置i插入+ 
	 sum+=a[i];   //计算结果 
	 fun(op,sum,a[i],a,i+1);  //继续处理下一个位置
	 sum-=a[i];   //回溯
	 op[i]='-';   //位置i插入-
	 sum-=a[i];  //计算结果
	 fun(op,sum,-a[i],a,i+1);  //继续处理下一个位置
	 sum+=a[i];  //回溯
	 op[i]=' ';    //在位置i插入‘’
	 sum-=prevadd;  //先减去前面的元素值
	 int tmp;   //计算新元素值
	 if(prevadd>0)
	 tmp=prevadd*10+a[i];   //如prevadd=5,a[i]=6,结果为56
	 else
	 tmp=prevadd*10-a[i];   //如prevadd=-5,a[i]=6,结果为-56
	 sum+=tmp;    //计算合并结果
	 fun(op,sum,tmp,a,i+1);  //继续处理下一个位置
	 sum-=tmp;   //回溯到sum 
	 sum+=prevadd; 
} 
void main(){
    
    
	int a[N];
	char op[N];   //op[i]表示在位置i插入运算符 
	for(int i=0;i<N;i++)   //将a赋值为1、2、...9
	a[i]=i+1;
	printf("求解结果\n");
	fun(op,a[0],a[0],a,1);  //插入位置i从1开始 
} 

在这里插入图片描述

  • 2.解空间为排列数

解空间为排列数的递归回溯框架

int X[n]; //X存放解向量,并初始化 
void backtrack(int i)   //求解排列数的递归框架 
{
    
    
	if(i>n)   //搜索到叶子结点,输出一个可行解 
	 输出结果; 
	 else
	 {
    
    
	 	for(j=i;j<=n;j++)  //用j枚举i的所有可能路径 
	 	{
    
    
	 		...   //第i层的节点选择X[j]的操作
	 		
	 			swap(X[i],X[j]);   //为保证排列中每个元素不同,通过交换实现
				 if(constrain(i)&&bound(i))
				 backtrace(i+1);  //满足约束条件和限界函数,进入下一层
				 swap(x[i],x[j]);   //恢复状态
				 ...   //第i层的节点选择x[j]的恢复操作 
		 }
	 }
}

问题描述:

在一个含有n个整数的数组a,所有元素均不相同,求其所有元素的全排列。
例:a[]={1,2,3},
得到的结果是(1,2,3)、(1,3,2)、(2,3,1)、(2,1,3)、(3,1,2)、(3,2,1)

采用递归回溯法——递归模型f(a,n,i)

f(a,n,i) 输出产生的解     若i=n
f(a,n,i) 对于j=i~n-1:a[i]与a[j]交换位置;  其他情况
    f(a,n,i+1);
    将a[i]与a[j]交换位置(恢复环境)

例:a[]={1,2,3},

在这里插入图片描述

在这里插入图片描述

代码:

#include<stdio.h>
void swap(int &x,int &y)   //交换x、y
{
    
    
	int tmp=x;
	x=y;
	y=tmp;
 } 
 void dispsolution(int a[],int n){
    
      //输出一个解
 printf("(");
 for(int i=0;i<n-1;i++)
 printf("%d, ",a[i]);
 printf("%d)",a[n-1]); 
 }
 void dfs(int a[],int n,int i)   //求a[0 ... n-1]的全排列
 {
    
    
 	if(i>=n)   //递归出口
	 dispsolution(a,n);
	 else
	 {
    
    
	 	for(int j=i;j<n;j++)
	 	{
    
    
	 		swap(a[i],a[j]);  //交换a[i]与a[j]
			 dfs(a,n,i+1);
			 swap(a[i],a[j]);  //交换a[i]与a[j] 
		 }
	  } 
  } 
  int main(){
    
    
  	int a[]={
    
    1,2,3};
  	int n=sizeof(a)/sizeof(a[0]);
  	printf("a的全排列\n");
  	dfs(a,n,0);
  	printf("\n");
  }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/gl620321/article/details/108694067