最后主导做一个考试系统,然而在为试卷出一份填空题的时候却遇到了麻烦,时间复杂度较大,耗时太长。虽然使用PHP开发,但是跟根我的经验,在数量级10^2级,出几个填空题竟然要花上5分钟来查找合适的题目,简直太扯淡了。
根据当前的实际情况:
1.题库中题目的空格数不连续且不确定
2.限制空数
3.题数可以不限定
4.要求在数秒之内生成题目
在询问PHP开发人员之后,发现找出方案的时间,确实常常在5分钟。使用C++实现并打印方案时,发现时间耗费也相当可怕。
稍后关闭所有打印,再次执行,发现30秒以内即可找出所有可能方案。方法如下:
void Situation(int nBlank/*空数*/,int min/*下限*/,int max/*上限*/, vector<int> &vec/*方案*/) { for (int i=min; i<=max; ++i) { vec.push_back(i);//压入当前值 int t = Sum(vec); if (t<nBlank) { Situation(nBlank,min,max,vec);//方案待完成 } else if (t == nBlank) { m_vv.push_back(vec);//得到方案 //PrintV(vec); //break; } else if (t > nBlank) { ;//break;//方案失败,一般不会到这儿 } vec.pop_back();//弹出当前值 } }
但是时间仍然长达30秒,且方案数达到数十万中,仍然需要优化,回想最开始根据每题的平均空数去取最大概率方案的方法,弊端也是显而易见的:
1.取不到其它方案
1.离平均空数较远的题恐怕永远选不到
因此想到了随机的方案:
1.每次从空格数队列中随机取出一个值,并将此值从本次取值的空格数队列中移除,表示取过了。空格数达不到要求则从最原始的空格队列 中取下一次值
2.直到取到最后一个值,此时空格数要么等于要求值,要么大于要求值
3.等于时,即成功取到方案,退出,大于时失败,需要回归到上一次,从余下的值中随机一个继续查找,直到取到等于的情况,则退出
方法如下:
int RandomV(vector<int> &v) { srand(time(NULL));//设定一个随机种子 int i = rand(); //在0-0x7fff取一个随机值 i = i%(v.size()-1);//换算队列的一个随机序号 int n = v[i];//取出该序号对应的值 v.erase(v.begin()+i);//从队列擦除该值 return n; } bool SituationVR(int nBlank,vector<int>const v,vector<int> &vec) { vector<int> v_ = v; //拷贝一个备份出来 for ( ; v_.size()>0; ) { int i = RandomV(v_); //从空格数队列中以时间作为种子,随机取出一个值,并删除已取过的值 vec.push_back(i); //压入当前值 int t = Sum(vec); //求当前累积空数 if (t<nBlank) //方案待完成 { if (SituationVR(nBlank,v,vec)) { return true; } } else if (t == nBlank) { PrintV(vec); m_vv.push_back(vec); //得到方案 return true; } else if (t > nBlank) { vec.pop_back(); //弹出当前值 break; //方案失败,一般不会到这儿 } vec.pop_back(); //弹出当前值 } return false; //默认返回假 }
每次执行时间几乎察觉不到,快速生成一个方案且结果随机。确实是一个生成填空题的绝佳算法。