description |
需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上。 网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方。 网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离)。 在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价。 |
input |
第一行为一个整数T,表示数据组数。 每组数据第一行为四个整数:N, M, A, B。 接下来的A+B行每行两个整数x, y,代表一个坐标,前A行表示各用户的坐标,后B行表示各通讯公司的坐标。 |
output |
对于每组数据输出一行"Case #X: Y",X代表数据编号(从1开始),Y代表所求最小代价。 |
sample_input |
1 3 3 4 1 1 2 2 1 2 3 3 2 2 2 |
sample_output |
Case #1: 4 |
hint |
数据范围 1 < T <20 1 < x < N 1 < y < M 1 < B < 100 1 < N, M < 100 1 < A < 100 |
暴力的算法不想发侮辱我博客了
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; typedef long long ll; int ax[1005], ay[1005], bx[1005], by[1005]; int n, m, a, b; ll cal2(int x, int y) { ll sum = 0; for(int i = 0; i < a; ++i) { sum += (ll)(x - ax[i]) * (x - ax[i]) + (ll)(y - ay[i])* (y - ay[i]); } int cur = 1e9; for(int i = 0; i < b; ++i) { cur = min(cur, abs(x-bx[i]) + abs(y-by[i])); } //printf("%d %d %lld\n", x, y, cur+sum); return sum + cur; } ll cal(int x) { int l = 1, r = m; int m, m1, m2; ll ans = -1, s1, s2; while(l <= r) { m = (r-l) / 3; m1 = l + m; m2 = r - m; s1 = cal2(x, m1); s2 = cal2(x, m2); if(s1 <= s2) { if(ans == -1 || s1 < ans) ans = s1; r = m2 - 1; } else { if(ans == -1 || s2 < ans) ans = s2; l = m1 + 1; } } return ans; } ll solve() { int l = 1, r = n; int m1, m2, m; ll ans = -1, s1, s2; while(l <= r) { m = (r - l) / 3; m1 = l + m; m2 = r - m; s1 = cal(m1); s2 = cal(m2); if(s1 <= s2) { if(ans == -1 || s1 < ans) ans = s1; r = m2 - 1; } else { if(ans == -1 || s2 < ans) ans = s2; l = m1 + 1; } } return ans; } int main() { int T, ca = 1; scanf("%d", &T); while(T--) { scanf("%d %d %d %d", &n, &m, &a, &b); for(int i = 0; i < a; ++i) scanf("%d %d", &ax[i], &ay[i]); for(int i = 0; i < b; ++i) scanf("%d %d", &bx[i], &by[i]); printf("Case #%d: %lld\n", ca++, solve()); } return 0; }