历届试题 邮局

时间:2022-01-07 17:31:44
问题描述
  C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流。为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信。

  现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
输入格式
  输入的第一行包含三个整数n, m, k,分别表示村民的户数、备选的邮局数和要建的邮局数。
  接下来n行,每行两个整数x, y,依次表示每户村民家的坐标。
  接下来m行,每行包含两个整数x, y,依次表示每个备选邮局的坐标。
  在输入中,村民和村民、村民和邮局、邮局和邮局的坐标可能相同,但你应把它们看成不同的村民或邮局。
输出格式
  输出一行,包含k个整数,从小到大依次表示你选择的备选邮局编号。(备选邮局按输入顺序由1到m编号)
样例输入
5 4 2
0 0
2 0
3 1
3 3
1 1
0 1
1 0
2 1
3 2
样例输出
2 4
数据规模和约定
  对于30%的数据,1<=n<=10,1<=m<=10,1<=k<=5;
  对于60%的数据,1<=m<=20;

  对于100%的数据,1<=n<=50,1<=m<=25,1<=k<=10。


其实没有想象中的那么难,慢慢做还是能得部分分的。测不过的是精度丢失。

import java.util.Scanner;

public class 邮局 {

static double[][] dp;
static int[] arr;
static boolean[] vis;
static double ans=Integer.MAX_VALUE;
static int[] out;
public static void main(String[] args) {

Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
int k=sc.nextInt();

int[][] cun=new int[n][2];
for (int i = 0; i < cun.length; i++) {
int x=sc.nextInt();
int y=sc.nextInt();
cun[i][0]=x;
cun[i][1]=y;
}

int[][] youju=new int[m][2];
for (int i = 0; i < youju.length; i++) {
int x=sc.nextInt();
int y=sc.nextInt();
youju[i][0]=x;
youju[i][1]=y;
}

dp=new double[m][n];
for (int i = 0; i < youju.length; i++) {
for (int j = 0; j < cun.length; j++) {
int h=youju[i][0]-cun[j][0];
int w=youju[i][1]-cun[j][1];
double l=Math.pow(Math.abs(w*w+h*h),0.5);
dp[i][j]=l;
}
}
arr=new int[k];
out=new int[k];
vis=new boolean[m];
dfs(arr,0,m,-1);
for (int i = 0; i < out.length; i++) {
System.out.print(out[i]+" ");
}
}
private static void dfs(int[] arr, int i, int m,int t) {

if(i==arr.length){
double sum=0;
for (int j = 0; j < dp.length; j++) {
//竖着最小值
double min=Integer.MAX_VALUE;
for (int k = 0; k < arr.length; k++) {
if(dp[arr[k]-1][j]<min){
min=dp[arr[k]-1][j];
}
}
sum+=min;
}

if(sum<ans){
for (int j = 0; j < arr.length; j++) {
out[j]=arr[j];
}
ans=sum;
}
return;
}

for (int j = t+1; j < m; j++) {
if(!vis[j]){
arr[i]=j+1;
t=j;
vis[j]=true;
dfs(arr,i+1,m,t);
vis[j]=false;
}
}
}
}