注意:
1、如果你是想多次*=的话,使用pow代替计算可以增加结果精确度
2、浮点数计算会有误差要注意判断条件
只拿了20分,想了两种递归的思路都是运行超时,不过应该可以为没有头绪的读者提供一点灵感,就先放出来了,日后再更新。
现在的情况是还需要优化效率,有一点头绪:分治法,把原问题分解成每层递归时可以计算的子问题进行计算,然后把计算结果记录下来,每层根据上一层的计算结果来推算。(用vector+动态规划尝试了下,还是超时,暂时放弃这题了)
//纯C,第一种思路:递归返回底层结果 逐层累积为最终结果(由底层到表层),20分,运行超时
#include
const double eps=1e-8;//浮点数运算误差值
int n,k;
double maby[16]={-1};
int haveCardCount[16]={0};//用于记录当前每种卡的抽到过次数
//深度优先搜索算法
double DFS(int coin,int count)//coin当前持有硬币数,count当前是第几次抽卡
{
int i,j,needCard=0;
double ans=0;
for(j=0;j<n;j++)
if(haveCardCount[j]==0)
needCard++;
if(coin/k+eps>=needCard)//完成一种游戏结果,系统栈出栈
{
ans = count;
}else
for(i=0;i<n;i++)//当前这一次抽卡的每种情况都需要枚举
{
if(haveCardCount[i]>0)
{
haveCardCount[i]++;
ans+=DFS(coin+1,count+1)*maby[i];
}
else
{
haveCardCount[i]++;
ans+=DFS(coin,count+1)*maby[i];
}
haveCardCount[i]--;
}
return ans;
}
int main()
{
int i;
scanf("%d %d",&n,&k);
for(i=0;i<n;i++)
scanf("%lf",&maby[i]);
printf("%.10f",DFS(0,0));
return 0;
}
//纯C,第二种思路:把计算结果设为全局变量 每次递归时累积(由表层到底层),10分,运行超时
#include
#include
const double eps=1e-8;//浮点数运算误差值
int n,k,needCard;//needCard还差几种卡
double maby[16]={-1};
int haveCardCount[16]={0};//用于记录当前每种卡的抽到过次数
double out=0;
//深度优先搜索算法
void DFS(int coin,int count)//coin当前持有硬币数,count当前是第几次抽卡
{
int i,j;
count++;
for(i=0;i<n;i++)//当前这一次抽卡的每种情况都需要枚举
{
int _coin=coin;
if(haveCardCount[i]>0)_coin++;
else needCard--;
haveCardCount[i]++;
if(_coin/k+eps>=needCard)//完成一种游戏结果,系统栈出栈
{
double tmp =1;
for(j=0;j<n;j++)
tmp*=pow(maby[j],haveCardCount[j]);//小细节pow一次性计算可以增加结果精确度
out+=tmp*count;
}else//递归下一次抽卡,系统栈压栈
{
DFS(_coin,count);
}
haveCardCount[i]--;
if(!haveCardCount[i])needCard++;
}
}
int main()
{
int i;
scanf("%d %d",&n,&k);
needCard=n;
for(i=0;i<n;i++)
scanf("%lf",&maby[i]);
DFS(0,0);
printf("%.10f",out);
return 0;
}
记录一下,下方是我的DFS第一版本代码,运行超时+准确度不足
(题目给的两个案例都准确完成,但是跟满分代码相比较后发现数据量大时准确度就不足了)
//10分代码,错误+运行超时
#include
#include
using namespace std;
double maby[16]={-1};
int haveCardCount[16]={0};
double out=0;
int n,k;
vector<int> v;
void DFS(int coin,int count)
{
int i,j,jj;
count++;
for(i=0;i<n;i++)
{
int _coin=coin;
haveCardCount[i]++;
for(vector<int>::iterator it=v.begin();it!=v.end();it++)
{
if(*it==i)
{
_coin++;
break;
}
}
v.push_back(i);
int needCard=0;
for(j=0;j<n;j++)
{
if(haveCardCount[j]==0)
needCard++;
}
if(1.0*_coin/k>=needCard)
{
double tmp =1;
for(j=0;j<n;j++)
{
for(jj=0;jj<haveCardCount[j];jj++)
tmp*=maby[j];
}
out+=tmp*count;
}else
{
DFS(_coin,count);
}
haveCardCount[*(v.end()-1)]--;
v.pop_back();
}
}
int main()
{
int i;
scanf("%d %d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%lf",&maby[i]);
}
DFS(0,0);
printf("%.10f",out);
return 0;
}
记录一下,下方是我的DFS第二版本代码,变成仅运行超时?!
第一版和第二版仅修改了判断条件,eps为“浮点数误差值”
第一版的判断条件if(1.0*_coin/k>=needCard)
第二版的判断条件if(1.0*_coin/k+eps>=needCard)
发现第一版错误是因为浮点数的比较问题!!!兄弟们以后写代码可记住这个问题了,别坏了大事
计算机中的浮点数存储不是绝对精准的,double类型可以存储约小数点后15~16位,当经过多次运算之后会出现很小很小的值误差变化,根据教科书上的说明,这个误差变化一般不会大于下面这个值
const double eps=1e-8;//科学记数法表示,10的-8次方
//10分代码,运行超时
#include
#include
using namespace std;
const double eps=1e-8;
double maby[16]={-1};
int haveCardCount[16]={0};
double out=0;
int n,k;
vector<int> v;
void DFS(int coin,int count)
{
int i,j,jj;
count++;
for(i=0;i<n;i++)
{
int _coin=coin;
haveCardCount[i]++;
for(vector<int>::iterator it=v.begin();it!=v.end();it++)
{
if(*it==i)
{
_coin++;
break;
}
}
v.push_back(i);
int needCard=0;
for(j=0;j<n;j++)
{
if(haveCardCount[j]==0)
needCard++;
}
if(1.0*_coin/k+eps>=needCard)
{
double tmp =1;
for(j=0;j<n;j++)
{
for(jj=0;jj<haveCardCount[j];jj++)
tmp*=maby[j];
}
out+=tmp*count;
}else
{
DFS(_coin,count);
}
haveCardCount[*(v.end()-1)]--;
v.pop_back();
}
}
int main()
{
int i;
scanf("%d %d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%lf",&maby[i]);
}
DFS(0,0);
printf("%.10f",out);
return 0;
}