回溯法
题目描述:
设计一个算法在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");
}