整数变换问题:整数i的两种变换定义为,(向下取整);设计一个算法求给定两个整数a和b,用最少次数的和变换将整数a变换为b;例如
题目分析:
观察f和g两个函数发现,f总是使得自变量x变大,g总是使得自变量x变小。因此我们在决定让x执行哪个函数之前必须先判断x和目标值m之间的大小关系。如果x>m,就让其执行g函数;反之,执行f函数。
这道题目有两种情况,一种是有解,即n可以通过函数变换成m;另一种是无解,即n无法通过函数变换成m。第一种情况比较容易,即只需要判断最后的x是否等于m即可。如果x等于m,那么说明n已经被变换成m了,递归返回。第二种情况,如果在递归的过程,出现了前面计算过的元素,那就说明n是无法转换成m的。
用回溯法解决整数变换问题,用子集树。
剪枝条件:
显示约束:如果x>m,就剪掉它的左子树;如果x<m,就剪掉它的右子树;
隐式约束:如果在某次计算的过程中发现当前的计算次数已经大于或等于最少计算次数了,就剪掉这个分支。
#include <stdio.h>
int a,b;
int k,found;
int *p;
int f(int i)
{
return 3*i;
}
int g(int i)
{
return i/2;
}
int changed(int m,int n)
{
int i,s;
if(m>k)return 0;
for(i=0;i<2;i++)
{
s=n;
if(i==0)s=g(s);
else s=f(s);
p[m]=i;
if(s==b||changed(m+1,s))
{
found=1;
return 1;
}
}
return 0;
}
void compared()
{
k=1;
found=0;
while(!changed(1,a))
{
k++;
if(k>100)break;
if(found!=0)break;
}
}
void main()
{
p=new int[100];
int i;
for(i=0;i<100;i++)p[i]=0;
printf("请依次输入a和b的值: ");
scanf("%d %d",&a,&b);
compared();
if(found)
{
printf("运算次数为: %d\n",k);
printf("运算转换过程为: ");
for(i=k;i>=1;i--)
{
if(p[i]==0)printf("g");
if(p[i]==1)printf("f");
}
}
else printf("%d 无法转换成%d ",a,b);
printf("\n");
}