Codeforces Gym101246J:Buoys(三分搜索)

http://codeforces.com/gym/101246/problem/J

题意:给出n个点坐标,要使这些点间距相同的话,就要移动这些点,问最少的需要的移动距离是多少,并输出移动后的坐标。

思路:昨晚比赛确定的一点就是通过X分搜索去枚举间距,使得最后的移动距离最短。

不过使用的是二分,而且写的时候也只枚举了起点和终点,后面想了要枚举所有的点,但时间来不及。

因为间距的单调不会使得答案单调,间距过大过小都会使得最后的移动距离不是最优,所以是使用三分而不是二分,顺便重温一下三分。

1     while(fabs(r - l) > eps) {
2         double mid = (l + r) / 2.0;
3         double midd = (mid + r) / 2.0;
4         if(cal(mid, 0) > cal(midd, 0)) l = mid;
5         else r = midd;
6     }
7     double ans = cal(l, 0) > cal(r, 0) ? r : l;

对于每次三分,每次在n个点里面假设一个点不动,然后枚举完算一遍,取最优。

而且据说挺卡精度的,直接开了1e-12.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 405
 4 const double eps = 1e-12;
 5 double num[N];
 6 int n, id;
 7 
 8 double cal(double x, int flag) {
 9     double res = 0, ans = 100000000;
10     for(int st = 1; st <= n; st++) {
11         res = 0;
12         for(int i = 1; i < st; i++)
13             res += fabs(num[st] - (st - i) * x - num[i]);
14         for(int i = st + 1; i <= n; i++)
15             res += fabs(num[st] + (i - st) * x - num[i]);
16         if(ans > res) ans = res, id = st;
17     }
18     return ans;
19 }
20 
21 void solve() {
22     scanf("%d", &n);
23     for(int i = 1; i <= n; i++) scanf("%lf", &num[i]);
24     double l = 0, r = 100000000;
25     while(fabs(r - l) > eps) {
26         double mid = (l + r) / 2.0;
27         double midd = (mid + r) / 2.0;
28         if(cal(mid, 0) > cal(midd, 0)) l = mid;
29         else r = midd;
30     }
31     double ans = cal(l, 0) > cal(r, 0) ? r : l;
32     double res = cal(ans, 1);
33     printf("%.4f
", res);
34     for(int i = 1; i < id; i++)
35         printf("%.10f ", num[id] - (id - i) * ans);
36     printf("%.10f ", num[id]);
37     for(int i = id + 1; i <= n; i++)
38         printf("%.10f ", num[id] + (i - id) * ans);
39 }
40 
41 int main() {
42     freopen("input.txt", "r", stdin);
43     freopen("output.txt", "w", stdout);
44     solve();
45     return 0;
46 }
原文地址:https://www.cnblogs.com/fightfordream/p/6495560.html