UVaLive 3708 Graveyard 墓地雕塑
2015-06-24 14:52
197 查看
题意:在一个周长为10000的圆上等距分布着n个雕塑。现又要加入m个雕塑,且使得这n + m个雕塑仍然等距分布。这就需要移动原来的某些雕塑。求移动原来的雕塑的距离和的最小值。
这道题需要分析和证明思路的正确性。直观看来,加入m个雕塑后这n + m个雕塑的位置相对而言应该是确定的(因为等距分布),而且原来的雕像只需要移动到加入雕像后的某个位置的雕像,且是最近的那个。看起来应该是正确的思路,但我们需要证明。
首先,我们假设原来的n个雕像全部都要移动。设原来n个雕像所在的点的集合为A,移动之后原来的n个雕像所在的点的集合为B。我们不妨假设集合A中有不少于一半的点是向逆时针方向移动的,那么我们将集合B中的这n个点每个点都不断的向顺时针方向移动相同的距离,显然不改变题目所要求的状态(因为新加入的m个点不参与计算移动的距离),且移动后与原来移动的总距离相比不会增加,可以理解为更优解。这样不断的移动,总可以在某个时候使B中的某个点与A中的某个点重合。这样即等价于A中至少有一个雕像没有移动。
这样,我们的思路就可以进一步了,就是原来的n个点至少有一个点是可以不动的,不妨设这个点的位置是0点时刻方向的位置。既然这个点不动,因为所有点等距分布,那么剩下的点的位置也就都是绝对确定的了。我们设在这个思路下,移动其他点之后以及加入了新的m个点之后,所有的n + m个点的集合为C。那么我们接下来证明,按照贪心思想,A集合剩下的n - 1个点每个点都移动到离它最近的C集合中的点,不会有两个点移动到同一个位置。
用反证法。假设A集合中有两个点X,Y移动到了C集合的同一个点Z。设C集合里与Z相邻的两个点为ZL,ZR。显然X,Y是分别夹在Z与ZL之间,Z与ZR之间的。我们不放假设X在Z与ZL之间,Y在Z与ZR之间。因为按照贪心思想,X到Z的距离(设为Dx)一定小于等于X到ZL的距离。进一步,可知Dx ≤ |Z - ZL |/2(用|A - B|表示点A和点B之间的距离,下同)。同理,Y到Z的距离Dy ≤ |Z - ZR|/2。显然|Z - ZL| = |Z
- ZR|(因为等距分布),我们假设这个距离为Dz。所以Dx + Dy ≤ Dz。另一方面,Dx + Dy可以表示原来等距的n个点里相邻两点的距离,而Dz是表示现在等距的n + m个点里相邻两点的距离,显然加入点之后这个距离应该更小,也就是应该满足Dx + Dy > Dz,这样得出了矛盾。所以不会有两个点移动到同一个位置。
至此问题就解决了。计算的时候我们用一个小技巧。假设现在n + m个点的等距为“单位1”(实际上是10000/(n + m)),我们按1计算出答案后乘上10000/(n + m)即可。因为现在n + m个点的等距为1,那么原来n个点的等距为(n + m)/n。不妨设那个不需要移动的点的坐标为0,那么现在n + m个点(C集合里所有点)的坐标为0 ~ n + m - 1,原来n个点的坐标(A集合中的点),第i个点为i*(n
+ m)/n,将这个坐标四舍五入得到的整数点即是离它最近的C集合里的点的坐标,相减取绝对值后加入总和即可求出答案,最后乘上10000/(n + m)即为最终答案。
这道题需要分析和证明思路的正确性。直观看来,加入m个雕塑后这n + m个雕塑的位置相对而言应该是确定的(因为等距分布),而且原来的雕像只需要移动到加入雕像后的某个位置的雕像,且是最近的那个。看起来应该是正确的思路,但我们需要证明。
首先,我们假设原来的n个雕像全部都要移动。设原来n个雕像所在的点的集合为A,移动之后原来的n个雕像所在的点的集合为B。我们不妨假设集合A中有不少于一半的点是向逆时针方向移动的,那么我们将集合B中的这n个点每个点都不断的向顺时针方向移动相同的距离,显然不改变题目所要求的状态(因为新加入的m个点不参与计算移动的距离),且移动后与原来移动的总距离相比不会增加,可以理解为更优解。这样不断的移动,总可以在某个时候使B中的某个点与A中的某个点重合。这样即等价于A中至少有一个雕像没有移动。
这样,我们的思路就可以进一步了,就是原来的n个点至少有一个点是可以不动的,不妨设这个点的位置是0点时刻方向的位置。既然这个点不动,因为所有点等距分布,那么剩下的点的位置也就都是绝对确定的了。我们设在这个思路下,移动其他点之后以及加入了新的m个点之后,所有的n + m个点的集合为C。那么我们接下来证明,按照贪心思想,A集合剩下的n - 1个点每个点都移动到离它最近的C集合中的点,不会有两个点移动到同一个位置。
用反证法。假设A集合中有两个点X,Y移动到了C集合的同一个点Z。设C集合里与Z相邻的两个点为ZL,ZR。显然X,Y是分别夹在Z与ZL之间,Z与ZR之间的。我们不放假设X在Z与ZL之间,Y在Z与ZR之间。因为按照贪心思想,X到Z的距离(设为Dx)一定小于等于X到ZL的距离。进一步,可知Dx ≤ |Z - ZL |/2(用|A - B|表示点A和点B之间的距离,下同)。同理,Y到Z的距离Dy ≤ |Z - ZR|/2。显然|Z - ZL| = |Z
- ZR|(因为等距分布),我们假设这个距离为Dz。所以Dx + Dy ≤ Dz。另一方面,Dx + Dy可以表示原来等距的n个点里相邻两点的距离,而Dz是表示现在等距的n + m个点里相邻两点的距离,显然加入点之后这个距离应该更小,也就是应该满足Dx + Dy > Dz,这样得出了矛盾。所以不会有两个点移动到同一个位置。
至此问题就解决了。计算的时候我们用一个小技巧。假设现在n + m个点的等距为“单位1”(实际上是10000/(n + m)),我们按1计算出答案后乘上10000/(n + m)即可。因为现在n + m个点的等距为1,那么原来n个点的等距为(n + m)/n。不妨设那个不需要移动的点的坐标为0,那么现在n + m个点(C集合里所有点)的坐标为0 ~ n + m - 1,原来n个点的坐标(A集合中的点),第i个点为i*(n
+ m)/n,将这个坐标四舍五入得到的整数点即是离它最近的C集合里的点的坐标,相减取绝对值后加入总和即可求出答案,最后乘上10000/(n + m)即为最终答案。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <stack> #include <queue> #include <vector> #include <map> #include <set> using namespace std; int n, m; void solve() { double ans = 0; double original = (double)(n + m)/n; //原来n个点的等距 for(int i = 0; i <= n; i++) { double temp = i*original; ans += fabs(temp - int(temp + 0.5)); // + 0.5是取四舍五入的技巧 } printf("%.4lf\n", ans*10000/(n + m)); } int main() { while(scanf("%d%d", &n, &m) != EOF) solve(); return 0; }
相关文章推荐
- Comparable与Comparator的区别
- iOS UIImageView 大小调整
- CorePlot学习 点击scatterPlot中的symbol点时弹出相应的注释
- 局域网手机遥控关机
- 深入研究java.lang.ThreadLocal类
- HDU 2102 A计划 (三维的迷宫BFS)
- 怎样使用复合索引优化一个分析函数SQL
- 最全SpringMVC详细示例实战教程
- 使用HTML辅助方法载入分部视图
- [leetcode] Gray Code
- 001 Ability
- hibernate使用version实现乐观锁
- wp7 webbrowser+html5 打造本地应用程序
- 线程间操作无效: 从不是创建控件“listView1”的线程访问它
- rz/sz yum install
- UE编辑器
- UFLDL(新版)中文翻译——Supervised Learning and Optimization: Linear Regression
- view如何从action中取得数据和 Html辅助方法
- ElasticSearch NEST
- 非常好的highcharts学习地址