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

来源:互联网 发布:云数据库的特点是什么 编辑:程序博客网 时间:2024/05/18 00:38

20150427更新

下午没有多少事情,逛到hihocoder上发现好多题目挂出来了,确认了一下第三题的思路是对的,提交之后发现是TLE,非常费解,,,两个小时之后,,,突然发现数组开错了,应该是pa[1005],pb[105] 对自己的代码能力已经越来越无语了~~~

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;typedef struct node{    long long int x,y;}node;int n,m,a,b;//node pa[105],pb[1005];//开错~~~~node pa[1005],pb[105];long long int getmin(long long int x,long long int y){    long long ans=0,tmp=0,tmp1=0;    int i;    for(i=0;i<a;i++){        ans+= (x-pa[i].x)*(x-pa[i].x) + (y-pa[i].y)*(y-pa[i].y);    }i=0;    tmp=abs(x-pb[i].x) + abs(y-pb[i].y);    for(i=1;i<b;i++){        tmp1=abs(x-pb[i].x) + abs(y-pb[i].y);        if(tmp1<tmp) tmp=tmp1;    }    return ans+tmp;}int main(){    int t,T,i,j,k;    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    scanf("%d",&T); //getchar();    for(t=1;t<=T;t++){        scanf("%d%d%d%d",&n,&m,&a,&b);        for(i=0;i<a;i++)scanf("%lld%lld",&pa[i].x,&pa[i].y);        for(i=0;i<b;i++)scanf("%lld%lld",&pb[i].x,&pb[i].y);        long long int sumx=0,sumy=0;        for(i=0;i<a;i++){            sumx+=pa[i].x; sumy+=pa[i].y;        }        long long int nx,ny,ans=-1;        nx=sumx/a; ny=sumy/a;        ans=getmin(nx,ny);        long long int stx,edx,sty,edy;        stx=(nx-3)>1?(nx-3):1;  sty=(ny-3)>1?(ny-3):1;        //该行dey错写<成了>        //edx=(nx+3)<n?(nx+3):n;  edy=(ny+3)>m?(ny+3):m;        edx=(nx+3)<n?(nx+3):n;  edy=(ny+3)<m?(ny+3):m;        for(nx=stx;nx<=edx;nx++){            for(ny=sty;ny<=edy;ny++){                if(ans==-1) ans=getmin(nx,ny);                else ans=min(ans,getmin(nx,ny));            }        }        printf("Case #%d: %lld\n",t,ans);    }    return 0;}

时间限制: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 ≤ 201 ≤ x ≤ N1 ≤ y ≤ M1 ≤ B ≤ 100小数据1N, M ≤ 1001 ≤ A ≤ 100大数据1N, M ≤ 1071 ≤ A ≤ 1000

样例输入

23 3 4 11 22 12 33 22 24 4 4 21 22 43 14 31 41 3

样例输出

Case #1: 4Case #2: 13

思路(由于代码写错了一个比较符号,只过了小数据,大数据TLE了):
求用A的平均点,即X坐标均值,Y坐标均值
以(X-3,Y-3)、(X+3,Y+3)确定一个候选坐标范围,枚举这个范围里的点,寻找答案。

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;typedef struct node{    long long int x,y;}node;int n,m,a,b;node pa[105],pb[1005];long long int getmin(long long int x,long long int y){    long long ans=0,tmp=0,tmp1=0;    int i;    for(i=0;i<a;i++){        ans+= (x-pa[i].x)*(x-pa[i].x) + (y-pa[i].y)*(y-pa[i].y);    }i=0;    tmp=abs(x-pb[i].x) + abs(y-pb[i].y);    for(i=1;i<b;i++){        tmp1=abs(x-pb[i].x) + abs(y-pb[i].y);        if(tmp1<tmp) tmp=tmp1;    }    return ans+tmp;}int main(){    int t,T,i,j,k;    scanf("%d",&T); //getchar();    for(t=1;t<=T;t++){        scanf("%d%d%d%d",&n,&m,&a,&b);        for(i=0;i<a;i++)scanf("%lld%lld",&pa[i].x,&pa[i].y);        for(i=0;i<b;i++)scanf("%lld%lld",&pb[i].x,&pb[i].y);        long long int sumx=0,sumy=0;        for(i=0;i<a;i++){            sumx+=pa[i].x; sumy+=pa[i].y;        }        long long int nx,ny,ans=-1;        nx=sumx/a; ny=sumy/a;        ans=getmin(nx,ny);        long long int stx,edx,sty,edy;        stx=(nx-3)>1?(nx-3):1;  sty=(ny-3)>1?(ny-3):1;        //该行dey错写<成了>        //edx=(nx+3)<n?(nx+3):n;  edy=(ny+3)>m?(ny+3):m;        edx=(nx+3)<n?(nx+3):n;  edy=(ny+3)<m?(ny+3):m;        for(nx=stx;nx<=edx;nx++){            for(ny=sty;ny<=edy;ny++){                if(ans==-1) ans=getmin(nx,ny);                else ans=min(ans,getmin(nx,ny));            }        }        printf("Case #%d: %lld\n",t,ans);    }    return 0;}
0 0