生肖迷宫之福娃吃蛋糕问题

来源:互联网 发布:济南联通软件研究院 编辑:程序博客网 时间:2024/04/20 13:18
【问题描述】

   5个福娃吃5个奥运蛋糕,1只福娃吃掉1个蛋糕需要60分钟,怎样才能确定一段30分钟的时间,太简单了,那么10分钟呢?还不难吧,但是9.5分钟呢?最后如何确定一段少于10秒钟的时间呢(不算0秒)?


这个问题是号称是生肖迷宫工作室为吸引高智商人才而特别设计的一道智力题,不过如果对程序员而言,这个问题其实还是很简单的问题,主要是思维转换,这个问题的本质和那个用M升的桶和N升的桶来倒出K升的水的问题,其实本质上而言都差不多。

这个问题我之前苦思冥想,尤其是最后10秒钟的方案,想了老半天,只能承认,我只是个凡人,不是天才。不过凡人有凡人解决问题的思路,就是将所有的可能的方案都遍历一遍,那么这个10秒钟的方案将无所遁形。

在考虑遍历之前,先需要对问题进行分析。
在任何时候,我们都只有五个福娃。
对于一个蛋糕,我们只有一个60分钟的蛋糕。


===============有两个蛋糕的情形===================================
对于2个蛋糕,我们可以得到如下情况
这个图第一行(1,2,30)表示,我们有两个一个福娃能吃60分钟的蛋糕,第一个蛋糕给1个福娃吃,第二个蛋糕给2个福娃吃,然后第二个蛋糕吃完时,第一个蛋糕会剩余的时间为30分钟(剩余时间为t的蛋糕是指一个福娃吃该蛋糕需要的时间)。
同样,第四行(2,3,10)就表示,第一个蛋糕2个福娃吃,第二个蛋糕3个福娃吃,当其中一个蛋糕吃完时,另一个蛋糕还剩余时间为10分钟。

对于两个蛋糕的情况,我们只能得到这四种结果,即剩余30分钟、40分钟、45分钟和10分钟的蛋糕。
=======================================================================

=================有三个蛋糕的情形======================================
然后我们再分析三个蛋糕的情况,三个蛋糕,只可能是1个60分钟的蛋糕,以及2个60分钟的蛋糕,由【有两个蛋糕的情形】的分析可知,三个蛋糕的情况,就是一个60分钟的蛋糕,以及一个【30分钟、40分钟、45分钟或10分钟】的蛋糕。

先分析一个60分钟蛋糕和一个30分钟蛋糕的情况

然后在分析一个60分钟蛋糕和一个40分钟蛋糕的情况

同样的方法分析一个60分钟蛋糕和一个45分钟蛋糕,以及一个60分钟蛋糕和一个10分钟蛋糕的情况。
==============================================================================

根据以上分析过程,可以直接编写程序来对这个过程进行实现了,个人编写了一个示例程序,能够实现基本功能,不过代码不是太美观,需要的就将就着看吧。


======================================================
#include <vector>
#include <set>
#include <math.h>
#include <fstream>
#include <iostream>
using namespace std;


struct resultStruct
{
double value;   ///保存剩余多少分钟的蛋糕
double val1;    ///保存要吃出value的蛋糕需要的蛋糕1
double val2; ///保存要吃出value的蛋糕需要的蛋糕1
int m; ///保存吃val1的蛋糕福娃数目
int n; ///保存吃val2的蛋糕福娃数目
bool mode; ///1表示以相加的方式,0表示以非相加(可能相减,可能N个福娃一起吃)的方式
int cakeNum;    ///要出现当前时间,需要的蛋糕数量。

bool operator < (const resultStruct& res) const
{
if( fabs(this->value - res.value) > 1e-8)
return this->value < res.value;

if( fabs(this->value - res.value) > 1e-8)
return this->val1 < res.val1;

if( fabs(this->value - res.value) > 1e-8)
return this->val2 < res.val2;

if( this->m != res.m)
return this->m < res.m;
else
return this->n < res.n;

//return this->cakeNum < res.cakeNum;


}
};

int main()
{
ofstream ofs("result.txt");
ofstream ofs2("result2.txt");
ofstream ofs3("result3.txt");
vector<set <resultStruct> > value;
value.resize(6);
//value[1].push_back(60);
resultStruct res;
res.value = 60;
res.m = 1;
res.n = 0;
res.val1 = 60;
res.val2 = 0;
res.mode = 0;
res.cakeNum = 1;
value[1].insert(res);

double temp=0;
resultStruct resStru;

///i表示有几个蛋糕对应的情况
for(int i=1;i<=5;i++)
{
///j表示由j个蛋糕情况和i-j个蛋糕情况组合成i个蛋糕情况
for(int j=1;j<=i/2;j++)
{
///j个蛋糕情况的循环
for(set<resultStruct>::iterator itA = value[j].begin(); itA != value[j].end(); itA++)
{
///i-j个蛋糕情况的循环
for(set<resultStruct>::iterator itB = value[i-j].begin(); itB != value[i-j].end(); itB++)
{
///吃itA->value对应的蛋糕需要的福娃数目
for(int m=1;m<5;m++)
///吃itB->value对应的蛋糕需要的福娃数目
for(int n=1;n<=5-m;n++)
{
resStru.value = fabs((itA->value)/m - (itB->value)/n);
resStru.val1 = itA->value;
resStru.val2 = itB->value;
resStru.m = m;
resStru.n = n;
resStru.mode = 0;
resStru.cakeNum = i;

///时间为0的不要
if(fabs(resStru.value) > 1e-10)
value[i].insert(resStru);
}
}
}
}
}

set<resultStruct> result1;  ///保存最终结果的
set<resultStruct> result2;  ///保存中间结果的
for(int i=1;i<=5;i++)
{
for(set<resultStruct>::iterator it = value[i].begin(); it != value[i].end(); it++)
{
if(fabs(it->value  - 50) < 1e-6)
{
int t=0;
}
result1.insert(*it);
///一块时间为T的蛋糕,可以被1~5个福娃吃,所以可以测得时间T,T/2,T/3,T/4和T/5五组时间
for(int j=1;j<=5;j++)
{
resStru.val1 =  it->value;
resStru.val2 = 0;
resStru.m = j;
resStru.n = 0;
resStru.value = resStru.val1/j;
resStru.mode = 0;
resStru.cakeNum = it->cakeNum;
result2.insert(resStru);
result1.insert(resStru);
}
}
}


for(set<resultStruct>::iterator it = result1.begin(); it != result1.end(); it++)
{
}

set<resultStruct> result3 = result2;
set<resultStruct> result4;

bool bChange = true;


///一块能吃出T1时间的蛋糕和一块能吃出T2时间的蛋糕,可以组合成T1+T2时间,如果蛋糕够的话
while(bChange)
{
bChange = false;

for(set<resultStruct>::iterator itA = result2.begin(); itA != result2.end(); itA++)
for(set<resultStruct>::iterator itB = result3.begin(); itB != result3.end(); itB++)
{
if(itA->cakeNum + itB->cakeNum <= 5)
{
resStru.val1 = itA->value;
resStru.val2 = itB->value;
resStru.cakeNum = itA->cakeNum + itB->cakeNum;
resStru.value = resStru.val1+resStru.val2;
resStru.m = 0;
resStru.n = 0;
resStru.mode = 1;
result4.insert(resStru);
result1.insert(resStru);
bChange = true;
}
}

result3 = result4;
result4.clear();
}
///输出所有结果

ofs<<"\n\t=====================================\n";
for(set<resultStruct>::iterator it = result1.begin(); it != result1.end(); it++)
{
ofs << it->value * 60 << "\t" << it->val1 * 60 << "\t" << it->val2 * 60
<< "\t" << it->m << "\t" << it->n << "\t" << it->cakeNum << "\t" << it->mode << endl;
}
ofs <<"\n======================================\n";


return 0;
}

======================================================


 


注意啊,我以上代码得到的结果不是最终的可测量时间数,而是一个福娃吃能吃T时间的蛋糕,由于这个蛋糕是可以得到的,这个时候五个福娃都闲着了,然后一个福娃吃能吃T时间,那么我们可以得到T,T/2,T/3,T/4以及T/5这五个时间。


由代码得到的,前面几组就太容易了,懒得写了,只写这个10s钟的,吃法如下:


 

从结果来看,能吃出10s的方案还不少,

我这里是列的第一个方案,其他的就不列了。

行了,这个题目算是解决完了,通过结果来看,能测量的时间很多啊。总共不同的方案数,程序运行出4339种,前面几种大约长得这个样子:
也就是,就结果而言,最小可以测得的时间是3.75s,是通过五个福娃一起吃18.75s的蛋糕得到的,而18.75s的蛋糕有五种方案得到,以此类推可以得到这个整体方案。




 

原创粉丝点击