nefu1039基地选址【三分】

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值