一个博物馆收藏了不同的火车,同地区的火车需要的铁路宽度不一样。现在这个博物馆为了陈列火车需要一些铁路,每条铁路可以看作是由两根平行钢轨组成的,只要把两条钢轨的距离摆放合适了,就可以放置对应的火车。
这个博物馆每次只展示一列火车,所以可以减少所需钢轨的数量。比如,如果有n列火车,他们需要的铁路宽度都不相同,那么只需要n+1条轨道就一定可以让每列火车都能够摆放。方法如下:把一条轨道放在最左边,剩下的n条钢轨里,第i条距离最左边轨道的距离和第i列火车需要的铁路宽度一样,这样n+1条铁轨就能够放下所有火车了。
【输入形式】
每个测试用例输入第一行包含n个整数n,表示火车所需要的铁路宽度的个数。接下来的一行有1
对每个测试用例输出一个整数,表示所需要的钢轨数量。
【样例输入】
4
1524 1520 1609 1435
【样例输出】
4
今天算法实验考试正好考了这道题,当时完全不会写…考完试之后突然恍然大悟,用十分钟写完了下面的代码。
完整代码:#include#include //需要使用到向量模板类 #include //需要使用到集合对向量进行去重 using namespace std; //采用概率算法,也就是通过循环得到多组可行解,判断可行解是否最优,当循环次数很大时由概率学知识可知当前最优解就是全局最优解 int Least_Num(const unsigned* Sizes, const unsigned& Num) { int min_Num = 10000000;//定义一个变量表示当前的最优解,初始化为一个很大的数字 for (int i = 0; i < 1000; i++)//循环一千次,每次循环得到一个可行解 { vector pos;//用一个向量记录当前的摆放位置 pos.push_back(0);//首先在坐标原点处摆放一根铁轨 for (unsigned j = 0; j < Num; j++) { loop: int Which_Num = rand() % pos.size();//通过随机数找出一根已经摆放了的钢轨的位置 int direction = rand() % 2;//确定下一根安放的钢轨是在找出的钢轨的左边还是右边 if (direction == 0)//方向为0表示在找出的钢轨的左边安放新钢轨 { if (pos[Which_Num] - Sizes[j] >= 0)//如果安放的位置已经大于坐标远点的位置,则属于可以安放的位置,安放铁轨并将安放位置记录下来 { pos.push_back(pos[Which_Num] - Sizes[j]); } else//如果想要安放的位置已经在原点的左边,那么就不合理了,此次循环无效,重复上述过程一遍(使用goto语句) { goto loop; } } else if (direction == 1)//方向为零表示在右边,此时安放位置没有限制,直接安放新的铁轨并记录位置即可 { pos.push_back(pos[Which_Num] + Sizes[j]); } } //使用集合对安放位置进行去重操作 set tempSet(pos.begin(), pos.end());//此时所有钢轨的安放位置都已经确定,得到了一个可行解,但是可能存在铁轨的安放位置重合,那么就可以节约一根铁轨 pos.assign(tempSet.begin(), tempSet.end());//将去重后的结果重新赋值给向量 if (pos.size() < min_Num)//判断是否需要更新局部最优解 { min_Num = pos.size(); } } return min_Num;//返回当前的最优解 } int main(void) { unsigned TrainNum; cin >> TrainNum; unsigned* TrainSize = new unsigned[TrainNum]; for (unsigned i = 0; i < TrainNum; i++) { cin >> TrainSize[i]; } cout << Least_Num(TrainSize, TrainNum); return 0; }



