又到了周末,怎么可以不发一篇总结文章,废话少说,直接进入正题。
在一个周长为10000的圆上等距分布着n个雕塑。现在又有m个新雕塑加入(位置可以随意放),希望所有n+m个雕塑在圆周上均匀分布。这就需要移动其中一些原有的雕塑。要求n个雕塑移动的总距离尽量小。2<=n<=1000, 1<=m<=1000,输出最小总距离,精确到10-4
其实,我很不善于处理以圆或以圈出现的题目,原因很简单,我所学过的数据结构中没有相应的结构与之对应。可不同的是,经过题目给出的样例输入和样例输出,我分析了一下,推测有一个雕塑是不需要移动的,就以这个点为起点,对其余各点进行编号,用数组A[]存储。同时,加入的m个点后的(n+m)个点的位置都是可以确定的,用数组B[]存储,
现在我们所要做的就是在这n+m个点中选出与原位置的n个点距离最近的n个点,由于原位置的点只可能转移到与原位置最近的左右两个位置,这点很重要,复杂的问题由于这个思想一下子变得很简单了,我们接下来所要做的就是构建一种很好的数据结构来存储这两个距离(到离最近的左边和离最近右边的距离),比较这两个距离之后就可以找到最近的移动距离,但这里会有一个问题:会不会有原来的两个点到分好之后的一个点的距离相等呢?理由是不可能会,这涉及到数学的推理,很简单就可以推出,分析到这里就差不多了,附上代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 2000;
struct sculpture
{
float left_distance;
float right_distance;
};
int main()
{
struct sculpture d[maxn];
int m,n;
//bool a[maxn];
while(scanf("%d%d",&m,&n) == 2)
{
float x = 10000 / m;
float y = 10000 /(n+m);
float A[maxn];
for(int i =0;i<m;++i)
{
A[i] = x * i;
}
float B[maxn];
for(int i = 0;i<(n+m);++i)
{
B[i] = y * i;
}
for(int i =1;i<m;++i)
{
for(int j =0;j<(n+m)-1;++j)
{
if(B[j] <= A[i] && A[i] <= B[j+1])
{
d[i].left_distance = A[i] - B[j];
d[i].right_distance = B[j+1] - A[i];
}
}
}
if((n+m)% m == 0)
{
cout << "0.0" << endl;
}
else
{
int sum = 0;
for(int i = 1;i<m;++i)
{
if(d[i].left_distance > d[i].right_distance)
sum += d[i].right_distance;
else
sum += d[i].left_distance;
}
printf("%0.4d",sum);
}
}
return 0;
}
接着就是蚂蚁问题了,说实话,这道题很像我概率论与数理统计期末考试中的最后一道题,题目是这样的:.n只蚂蚁以1cm/s的速度在长为L的竿上爬行,当蚂蚁爬到竿子的端点就会掉落。当两只蚂蚁相撞时,只能各自反向爬回去。对于每只蚂蚁,给出距离左端的距离xi,但不知道它的朝向,要求按输入顺序输出 t 秒后每只蚂蚁的位置和状态(掉出去,转向中,或者蚂蚁的朝向)。
首先确定,两只蚂蚁的相撞点不一定是整厘米处,因此单位时间应该是0.5秒,每过一个0.5秒都应该检测是否有相撞或落下等情况发生。这样做是可行的,我又看了一下书上的解答,思路很简单,相撞后,蚂蚁之间的相对次序并没有发生变化,这点很重要。
有关细节方面的知识,比如,结构体数组中运算符的重载,我觉得挺好用的。
struct Ant
{
int id; //输入顺序
int p; //位置
int d; //朝向
bool operator < (const Ant& a) const //结构体内运算符重载
{
return p < a.p;
}
}