2015编程之美资格赛题目3 : 基站选址

描述

需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上。

网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方。

网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离)。

在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价。

输入

第一行为一个整数T,表示数据组数。

每组数据第一行为四个整数:N, M, A, B。

接下来的A+B行每行两个整数x, y,代表一个座标,前A行表示各用户的座标,后B行表示各通讯公司的座标。

输出

对于每组数据输出一行”Case #X: Y”,X代表数据编号(从1开始),Y代表所求最小代价。

数据范围

1 ≤ T ≤ 20

1 ≤ x ≤ N

1 ≤ y ≤ M

1 ≤ B ≤ 100

小数据

1 ≤ N, M ≤ 100

1 ≤ A ≤ 100

大数据

1 ≤ N, M ≤ 107

1 ≤ A ≤ 1000

样例输入

2
3 3 4 1
1 2
2 1
2 3
3 2
2 2
4 4 4 2
1 2
2 4
3 1
4 3
1 4
1 3

样例输出

Case #1: 4

Case #2: 13

刚开始以为是最小代价生成树的问题,其实是个数学问题,求平面上一点到n个点的距离最小。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <limits>
#define MOD 100007
using namespace std;

int m , n , num_a,num_b, x, y;
int x1[1001], y1[1001], x2[1001], y2[1001]; 
long long sum_x, sum_y, ans ,ans_x, ans_y;

void find_ans(int x, int y) {
	int s = 0, temp = INT_MAX;

	for (int k = 1; k <= num_1; k++)
		s += (x1[k] - x) * 1LL * (x1[k] - x) + (y1[k] - y) * 1ll * (y1[k] - y);
	for (int k = 1 ; k <= num_b; k++)
		temp = min(temp, abs(x2[k]-x) + abs(y2[k]-y)*1LL);
	if(s+temp <ans) {
		ans = s+temp;
	}
}


int main()
{
    int T,num;
    scanf("%d", &T);
    for ( num = 1; num <= T; num++ )
    {
		scanf("%d %d %d %d",&m,&n,&num_a,&num_b);
		sum_x = 0;
		sum_y = 0;
		for (int i = 1 ; i <= num_a; i++) {
			scanf("%d %d", &x1[i], &y1[i]);
			sum_x += x1[i];
			sum_y += y1[i];
		}
		for (int i = 1 ; i <= num_b; i++)
			scanf("%d %d", &x2[i], &y2[i]);
		x = sum_x / num_a;
		y = sum_y / num_b;
		ans = INT_MAX;
		for (int i = x-1; i <= x+1; i++)
			for (int j = y-1; j <= y+1; j++){
				if ( i >= 1 && i <= n && j >=1 && j <=m)
					find_ans(i,j);
			}
        printf("Case #%d: %d\n",num,ans);
    }
    return 0;
}

点赞