题:
时间限制: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
本题可以用图论的方法实现,但是不论是对空间的要求还是对时间的要求都很大,此题可以简化为一维线上的距离问题
简化1:
首先要注意到A的距离在最后结果中的重要程度远大于B的距离,即简单的平方权重大
简化2:
类似于LMS,求最佳逼近直线必然通过x坐标的平均值点(xx)和y的平均值点(yy),即应选择这两点搭建基站
简化3:
此时再考虑B的距离,因为坐标必须在格点,所以当(xx)(yy)不为证书时,应在其四周搜索
代码如下
#include <iostream>
#include <vector>
#include <string>
#include <vector>
#include <math.h>
using namespace std;
#define modnum 100007
long long cost=0;
long long maxll=9223372036854775807;
long long mincost=maxll;
long long sx=0;
long long sxs=0;
long long sy=0;
long long sys=0;
vector<long long> bx;
vector<long long> by;
int N,M,A,B;
long long cal(long long ss,long long s,long long x,long long num)
{
long long ans=0;
ans=ss+num*x*x-2*s*x;
return ans;
}
long long calA(long long x,long long y)
{
long long ans=maxll;
for(int i=0;i<bx.size();i++)
{
ans=(ans>abs(bx[i]-x)+abs(by[i]-y))?abs(bx[i]-x)+abs(by[i]-y):ans;
}
return ans+cal(sxs,sx,x,A)+cal(sys,sy,y,A);
}
int main()
{
int T=0;
int Case=0;
cin>>T;
while(T)
{
bx.clear();
by.clear();
sx=0;
sxs=0;
sy=0;
sys=0;
T--;
Case++;
cin>>N>>M>>A>>B;
int temp=0;
for(int i=0;i<A;i++)
{
cin>>temp;
sx+=temp;
sxs+=temp*temp;
cin>>temp;
sy+=temp;
sys+=temp*temp;
}
for(int i=0;i<B;i++)
{
cin>>temp;
bx.push_back(temp);
cin>>temp;
by.push_back(temp);
}
long long x,y;
x=sx/A;
y=sy/A;
long long ans=maxll;
ans=min(ans,calA(x,y));
ans=min(ans,calA(x,y+1));
ans=min(ans,calA(x+1,y));
ans=min(ans,calA(x+1,y+1));
cout<<"Case #"<<Case<<": "<<ans<<endl;
}
}