Google题解

Kickstart2017 RoundB

B.题意: 二维平面上有n个点, 每个点坐标(xi, yi), 权值wi, 问: 在平面上找一点p, 使得 Σwi*max(|X-xi|, |Y-yi|)最小, (X, Y)为p点坐标。求该最小值。

二维空间:

欧几里得距离:d=√(|x1-x2|2+|y1-y2|2)

曼哈顿距离 :d=|x1-x2|+|y1-y2|,到某点的曼哈顿距离为r的点组成一个边长为√2*r的正方形,且边与坐标轴成45度

切比雪夫距离:d=max(|x1-x2|,|y1-y2|),到某点的切比雪夫距离为r的点组成一个边长为2*r的正方形,且边与坐标轴平行

  1 /*
  2 题解: 赛后看到有不少随机化算法可乱搞过去
  3 该题是二维平面邮局距离(参见《算法导论》)的变形
  4 
  5 simple版:一维下, 使得Σwi*|X-xi|最小, 其中所有wi = 1. 答案显然为xi的中位数
  6 middle版:我们可以将wi看成有wi个点重合, 权值均为1, 则可套用simple版解法
  7 hard版:二维下, 使得 Σwi*(|X-xi| +|Y-yi|)最小. X轴, Y轴分开解即可
  8 此题:我们将整个平面旋转45°即可变为hard版. 为什么?
  9 
 10 因为hard中|X-xi| +|Y-yi|表示的边界形状为以(xi, yi)为中心的45°倾斜的正方形
 11 而本题max(|X-xi|, |Y-yi|)表示的边界形状为以(xi, yi)为中心的正方形
 12 */
 13 
 14 #include <iostream>
 15 #include <algorithm>
 16 #include <vector>
 17 #include <string>
 18 #include <unordered_set>
 19 #include <unordered_map>
 20 #include <set>
 21 #include <map>
 22 #include <queue>
 23 #include <stack>
 24 #include <functional>
 25 #include <cmath>
 26 #include <string.h>
 27 
 28 using namespace std;
 29 using ull = unsigned long long;
 30 using ll = long long;
 31 using db = double;
 32 using PII = pair<int, int>;
 33 
 34 template<typename T>
 35 void print_vec(T& container, const std::string& sep = " "){
 36     for (auto& x: container){
 37         std::cout << x << sep;
 38     }
 39     std::cout << std::endl;
 40 }
 41 
 42 template<typename T>
 43 void print_map(T& mp){
 44     for(auto& x: mp){
 45         std::cout << x.first << " " << x.second << std::endl;
 46     }
 47 }
 48 
 49 struct Point{
 50     double x, y, w;
 51     void input(){
 52         cin >> x >> y >> w;
 53     }
 54     double dist(double _x, double _y){
 55         return fabs(x - _x) + fabs(y - _y);
 56     }
 57     void rotate(){
 58         static double ang = 45.0 / 180 * acos(-1.0);
 59         double x1 = x * cos(ang) - y * sin(ang);
 60         double y1 = x * sin(ang) + y * cos(ang);
 61         x = x1 * sin(ang) ;
 62         y = y1 * sin(ang) ;
 63     }
 64 };
 65 struct Problem{
 66 
 67     int N;
 68     Point p[10010];
 69     void read(){
 70         cin >> N;
 71         for (int i = 0; i < N; i++){
 72             p[i].input();
 73             p[i].rotate();
 74         }
 75     }
 76 
 77     struct WEIGHT{
 78         double w;
 79         double x;
 80         bool operator<(const WEIGHT& wt) const{
 81             return x < wt.x;
 82         }
 83     };
 84 
 85     double calc(WEIGHT wt[], int n){
 86         sort(wt, wt + n);
 87         double ans = 0;
 88         double cur_x = wt[0].x;
 89         double pre_sum = 0;
 90         double suf_sum = 0;
 91         for (int i = 0; i < n; i++){
 92             ans += (wt[i].x - cur_x) * wt[i].w;
 93             suf_sum += wt[i].w; 
 94         }
 95         double ret = ans;
 96         for (int i = 1; i < n; i++){
 97             double nxt_x = wt[i].x;
 98             suf_sum -= wt[i-1].w;
 99             pre_sum += wt[i-1].w;
100             ans -= suf_sum * (nxt_x - cur_x);
101             ans += pre_sum * (nxt_x - cur_x);
102             cur_x = nxt_x;
103             ret = min(ans, ret);
104         }
105         return ret;
106     }
107     void solve(int ca){
108         printf("Case #%d: ", ca);
109         
110         WEIGHT vx[10010], vy[10010];
111         for (int i = 0; i < N; i++){
112             vx[i].x = p[i].x;
113             vx[i].w = p[i].w;
114             vy[i].x = p[i].y;
115             vy[i].w = p[i].w;
116         }
117         double sum = calc(vx, N) + calc(vy, N);
118         printf("%.7f\n", sum);
119     }
120 };
121 
122 int main(){
123     int T;
124     cin >> T;
125     for (int ca = 1; ca <= T; ca++){
126         Problem p;
127         p.read();
128         p.solve(ca);
129     }
130 }
View Code

 附随机化模拟退火算法:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <climits>
 9 #include <stack>
10 #include <queue>
11 #include <ctime>
12 #include <string>
13 #include <iostream>
14 #include <algorithm>
15 using namespace std;
16 
17 #define MEM(a,b) memset(a,b,sizeof(a))
18 #define REP(i,n) for(int i=0;i<(n);++i)
19 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const int MAXN = 10010;
27 const double cof = 0.5;
28 const double eps = 1e-3;
29 const double deta = 0.7;
30 
31 int T,N;
32 double X[MAXN],Y[MAXN], W[MAXN];
33 int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
34 
35 double Dis(double a1,double b1,double a2,double b2){
36     return max(abs(a1-a2), abs(b1-b2));
37 }
38 
39 double Cal(double a,double b){
40     double res = Dis(a,b,X[0],Y[0]) * W[0];
41     FOR(i,1,N - 1) res += Dis(a,b,X[i],Y[i]) * W[i];
42     return res;
43 }
44 
45 int main(){
46     srand((unsigned)time(NULL));
47     int a,b;
48     scanf("%d",&T);
49     FOR(tt,1,T){
50         scanf("%d",&N);
51         REP(i,N) scanf("%lf%lf%lf",&X[i],&Y[i], &W[i]);
52         double ans = -1,ansx,ansy;
53         REP(o,100){
54             double sx = rand() % (N + 1);
55             double sy = rand() % (N + 1);
56             double res = Cal(sx,sy);
57             double step = N;
58             while(step > eps){
59                 while(1){
60                     bool mov = false;
61                     REP(k,4){
62                         double tx = sx + dir[k][0] * step;
63                         double ty = sy + dir[k][1] * step;
64                         if(tx < -10000 || tx > 10000 || ty < -10000 || ty > 10000) continue;
65                         double tmp = Cal(tx,ty);
66                         if(tmp < res || (double)rand()/INT_MAX > deta){
67                             res = tmp;
68                             sx = tx;
69                             sy = ty;
70                             mov = true;
71                         }
72                     }
73                     if(mov == false) break;
74                 }
75                 step *= cof;
76             }
77             if(ans == -1 || res < ans){
78                 ans = res;
79                 ansx = sx;
80                 ansy = sy;
81             }
82         }
83         printf("Case #%d: %.6lf\n", tt, ans);
84         //printf("The safest point is (%.1f, %.1f).\n",ansx,ansy);
85     }
86     return 0;
87 }
View Code

 

posted @ 2017-05-07 19:09  我在地狱  阅读(365)  评论(2编辑  收藏  举报