DFS-邮局

问题描述
  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。

思路:直接暴力,搜索m个邮局里面选出k个的组合,然后求其中使得距离和最小的方案。这里面不要全部k个搜完,

在二重循环求当前邮局方案所对应的距离和,而是应该每多安排一个邮局,就更新一下到各村民家的最小距离值,

即 nowdist[nown][j]=min(nowdist[nown-1][j],dist[j][i])(其中nown表示当前已经搜到第nown个邮局,而i表示该邮局尝试的编号)

最后即是求nowdist[k][1]+~+nowdist[k][n]的最小值所对应的方案res[1],~,res[k]

代码:

import java.util.Scanner;  

public class Main{  
    static int i, n, m, k;  
    static double ans;  
    static int x[], y[], xpost[], ypost[], ansarr[], res[];  
    static double dist[][], nowdist[][];  

    private static void show(int arr[]) {  
        for (int i = 1; i <= k; i++)  
            System.out.print(arr[i] + " ");  
        System.out.println();  
    }  
     //nown表示当前已经搜到第nown个邮局
    //
   //
    private static void dfs(int num, int nown, int last) {  
        if (nown == k + 1) {  //k:要建的邮局数
            double sumdist = 0;  
            for (int i = 1; i <= n; i++)  
                sumdist += nowdist[k][i];  
            if (sumdist < ans) {  
                ans = sumdist;  
                ansarr = res.clone();  
            }  
            return;  
        }  
        for (int i = num; i <= last; i++) {  
            for (int j = 1; j <= n; j++)  //n:村民户数
                nowdist[nown][j] = nowdist[nown - 1][j] < dist[j][i] ? nowdist[nown - 1][j]  
                        : dist[j][i];  
            res[nown] = i;  
            dfs(i + 1, nown + 1, last + 1);  
            res[nown] = 0;  
        }  
    }  

    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        Scanner scanner = new Scanner(System.in);  
        n = scanner.nextInt();  //村民的户数
        m = scanner.nextInt();  //备选的邮局数
        k = scanner.nextInt();  //要建的邮局数
        x = new int[n + 1];  //每户村民的坐标
        y = new int[n + 1];  
        xpost = new int[n + 1];  //每个备选邮局的坐标
        ypost = new int[n + 1];  
        for (int i = 1; i <= n; i++) {  
            x[i] = scanner.nextInt();  
            y[i] = scanner.nextInt();  
        }  
        for (int i = 1; i <= m; i++) {  
            xpost[i] = scanner.nextInt();  
            ypost[i] = scanner.nextInt();  
        }  
        ansarr = new int[k + 1];  //存储结果
        ans = Integer.MAX_VALUE;  
        dist = new double[n + 1][m + 1];  //距离
        res = new int[k + 1];  
        for (int i = 1; i <= n; i++)  
            for (int j = 1; j <= m; j++) {  
                double xsqr = (x[i] - xpost[j]) * (x[i] - xpost[j]);  
                double ysqr = (y[i] - ypost[j]) * (y[i] - ypost[j]);  
                dist[i][j] = Math.sqrt(xsqr + ysqr);  
            }  

        nowdist = new double[k + 1][n + 1];  
        for (int i = 1; i <= n; i++)  
            nowdist[0][i] = Integer.MAX_VALUE / n;  

        dfs(1, 1, m - k + 1);  
        show(ansarr);  
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值