整数变换问题

整数变换问题:整数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");

}

整数变换问题指的是,给定两个整数 a 和 b,允许执行以下两个操作之一: 1. 将 a 加上 b 的值; 2. 将 b 加上 a 的值。 求通过若干次这两个操作,能否将 a 变换成 b。 正确性证明如下: 首先,我们可以证明,对于任意两个正整数 a 和 b,它们能够通过若干次操作变换到一起,当且仅当它们的最大公约数能够整除它们的差值。 证明如下: 设 a 和 b 的最大公约数为 d,则 a = d * x,b = d * y,其中 x 和 y 互质。 假设我们通过若干次操作将 a 变换成 b,变换过程中,a 和 b 分别变换成了 a' 和 b'。则有: a' = a + k * b = d * x + k * d * y = d * (x + k * y) b' = b + m * a = d * y + m * d * x = d * (y + m * x) 其中 k 和 m 均为非负整数。 由于 x 和 y 互质,因此 x + ky 和 y + mx 也是互质的。因此,如果 a 和 b 能够通过若干次操作变换到一起,那么必然存在非负整数 k 和 m,使得 x + ky = y + mx。 将其变形得: (k - m) * y = (x - y) * m 由于 x 和 y 互质,因此 x - y 和 y 是互质的,因此必然存在 m 的逆元 m',使得 m' * (x - y) ≡ y (mod k - m)。 因此,我们可以取 k = m + m' * (x - y),得到一个满足条件的 k。此时,我们可以通过若干次操作将 a 变换成 b。 反之,如果 a 和 b 的最大公约数不能整除它们的差值,那么显然无法通过若干次操作将 a 变换成 b。 因此,我们可以通过检查 a 和 b 的最大公约数是否能够整除它们的差值,来判断它们能否通过若干次操作变换到一起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯子佳人傻了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值