经典算法之不定方程问题
所谓不定方程,是指未知数个数多于方程个数,且对解都有一定的限制。
首先,来看一道经典的数学问题“百钱买鸡”问题。
中国古代数学家张丘建在他的《算经》中提出了著名的“百钱买鸡”问题:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买鸡,问翁、母、雏各几何?
意思是:公鸡5文钱1只,母鸡3文钱1只,小鸡3只1文钱,要求100文钱买100只鸡,求公鸡、母鸡和小鸡应该各买多少只?
其实这是一道不定方程问题,有两个条件:一是用的钱数正好是100文;二是买鸡的数量正好是100只。设买公鸡、母鸡和小鸡分别为x、y、z只,则可列出一下方程:
x+y+z = 100
5x+3y+z/3 = 100
根据这两个公式,通过计算机的穷举算法即可求得结果。
代码一:
void BuyChicken() { int x,y,z; for(x = 0; x <= 20; x++) { for(y = 0; y <= 33; y++) { z = 100 - x - y; if(z % 3 == 0 && x*5 + y*3 + z/3 == 100) { printf("公鸡:%d,母鸡:%d,小鸡:%d\n",x,y,z); } } } }
以上的算法并不是最佳的,深入分析,4只公鸡值20文钱,3只小鸡值1文钱,合起来鸡数是7,钱数是21;而7只母鸡的钱数也正好是21.如果少买7只鸡,就可以用这笔钱多买4值公鸡和3只小鸡。这样,百钱还是百钱,百鸡还是百鸡。所以,只要求出一个答案,根据这个规则,马上就可以求出其他的答案出来。
设一个参数看,则有:
x = 4k;
y = 25 - 7k;
z = 75 + 3k;
因为鸡的数量x、y、z都只能是正数,所以满足式子的k值只能是0、1、2、3.
代码二:
void BuyChicken2()
{
int x,y,z,k;
for(k = 0; k <= 3; k++)
{
x = 4*k;
y = 25 - 7*k;
z = 100 - x - y;
printf("公鸡:%d,母鸡:%d,小鸡:%d\n",x,y,z);
}
}
其次,还有大家都非常熟悉的趣味数学题“鸡兔同笼”问题。
问题的描述是:有若干只鸡兔同在一个笼子里,从上面数,有35个头;从下面数,有94只脚。求笼子中有多少只鸡和多少只兔?
这个问题用穷举法可以解决,设有鸡x只,兔y只,则有方程:
x + y = 35;
2x + 4y = 94;
代码三:
void Chook_Rabbit()
{
int chook,rabbit,head,foot;
printf("请输入头数和脚数:");
scanf("%d%d",&head,&foot);
for(chook = 0; chook <= head; chook++)
{
rabbit = head -chook;
if(chook * 2 + rabbit * 4 == foot)
{
printf("鸡有:%d只,兔子有:%d只。",chook,rabbit);
}
}
}
仔细分析,还有更简单的方法,用奥数中的知识:
将每个头都按2只算(则认为都是鸡),则剩下的足就是兔子的另两只,则只需要将剩下的足除以2即可得到兔子的数量。
代码四:
void Chook_Rabbit1()
{
int chook,rabbit,head,foot;
printf("请输入头数和脚数:");
scanf("%d%d",&head,&foot);
rabbit = (foot - 2*head)/2;
chook = head - rabbit;
printf("鸡有:%d只,兔子有:%d只。",chook,rabbit);
}
最后再来看一道著名的“五家共井”问题。
问题的描述:今有五家共井,甲二绠不足如乙一绠,乙三绠不足如丙一绠,丙四绠不足如丁一绠,丁五绠不足如戊一绠,戊六绠不足如甲一绠。如各得所不足一绠,皆逮。问井深、绠长几何?(题中:“绠”是汲水桶上的绳索,“逮”是到达井底水面的意思。)
意思是:现在有5家共用一口井,甲、乙、丙、丁、戊5家各有一条绳子打水,设各家绳子的长度分别为len1,len2,len3,len4,len5,井深len,则以上条件可以表示为下面的方程:
len1*2+len2 = len;
len2*3+len3 = len;
len3*4+len4 = len;
len4*5+len5 = len;
len5*6+len1 = len;
求井的深度和各家打水所用绳子的长度。
根据上面的方程可得到一下算式:
len1*2 + len2 = len2*3+len3 = len3*4+len4 = len4*5 +len5 = len5*6+len1
由以上算式可以推出:
len1 = len2 + len3/2
len2 = len3 + len4/3
len3 = len4 + len5/4
len4 = len5 + len1/4
根据以上列出的这些算式,可枚举各种情况,最后得出结果。
代码五:
void Length()
{
int len1,len2,len3,len4,len5,len,flag;
flag = 1;
len5 = 0;
while(flag)
{
len5 += 4; //len5为4的倍数
len1 = 0;
while(flag)
{
len1 += 5; //len1为5的倍数
len4 = len5 + len1/5; //丁家井绳长
len3 = len4 + len5/4; //丙家井绳长
if(len3 % 2) //若不能被2整除
continue;
if(len4 % 3) //若不能被3整除
continue;
len2 = len3 + len4/3;
if(len2 + len3 / 2 < len1) //不符合条件
break;
if(len2 +len3 / 2 == len1) //符合条件
flag = 0;
}
}
len = 2*len1 + len2;
printf("各家井绳长度分别为:\n");
printf("甲:%d\n",len1);
printf("乙:%d\n",len2);
printf("丙:%d\n",len3);
printf("丁:%d\n",len4);
printf("戊:%d\n",len5);
printf("井深:%d\n",len);
}
转载请标明出处:http://blog.csdn.net/u012027907/article/details/12587589