时间限制:
2000ms 单点时限:
1000ms 内存限制:
256MB
描述
需要在一个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
题解:只考虑用户的话,最优解的坐标为(x的平均值,y的平均值)。写出公式,然后求导即可证明。再考虑基站,由于是曼哈顿距离,写出公式,容易证明出基站是不影响最优解的坐标的。代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#define nn 1100
typedef long long LL;
const int inf=0x3fffffff;
const LL inf64=(LL)inf*inf;
using namespace std;
LL sumx,psumx,sumy,psumy;
int n,m,A,B;
LL bx[nn],by[nn];
LL solvex(LL x,int id)
{
return x*x*A+psumx-2*x*sumx+abs(x-bx[id]);
}
LL solvey(LL y,int id)
{
return y*y*A+psumy-2*y*sumy+abs(y-by[id]);
}
int main()
{
int t,i;
int cas=1;
scanf("%d",&t);
LL x,y;
while(t--)
{
scanf("%d%d%d%d",&n,&m,&A,&B);
sumx=psumx=sumy=psumy=0;
for(i=1;i<=A;i++)
{
scanf("%lld%lld",&x,&y);
sumx+=x;
psumx+=x*x;
sumy+=y;
psumy+=y*y;
}
LL ans=inf64;
LL ansx,ansy;
for(i=1;i<=B;i++)
{
scanf("%lld%lld",&bx[i],&by[i]);
ansx=min(solvex(sumx/A,i),solvex(sumx/A+1,i));
ansy=min(solvey(sumy/A,i),solvey(sumy/A+1,i));
ans=min(ans,ansx+ansy);
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}