小镇广告牌

小镇广告牌
题目描述:已知某小镇的房子沿直线分布,给定一个有序整数数组arr,里面的每个镇代表小镇每栋房子的一维坐标点。现在需要建N个广告牌,广告牌只能建立在这些坐标点上,使得每个坐标点离广告牌的总距离最短,求这个最短的总距离。

输入描述:输入最后一个为N值,其余的为arr值,需要考生自行处理。

例如:输入1 2 3 4 5 1000 2,输出6。

解答:

      首先理解题目的意思,当广告牌有一个的时候,小镇只选择这个广告牌计算距离;当广告牌有两个的时候,小镇就可以选择其中一个广告牌计算距离,当然要保证获取的是最短的距离。这是一道动态规划的问题,问题解决的目的是用最小的代价连接所有的点,其用到的策略就是贪心算法。

     所以遵循这个原则,从最优解开始,要先获取到某个点与其他点的距离。当去选择广告牌时可以先确认两点,比如第一位置和第五位置,以中间第三位置放广告牌就是最优解,获取到3与1~5的距离,获取到局部的最优解

   arr[] = {1,2,3,4,5,1000}

 dis [0,4] = arr[2]-arr[0];   2
 dis [0,4] = arr[2]-arr[1];   1
 dis [0,4] = arr[2]-arr[2];   0
 dis [0,4] = arr[2]-arr[3];   1
 dis [0,4] = arr[2]-arr[4];   2  

算出来的总距离为6,这就是以3作为广告牌与1~5的最短总距离。这就是1~5的局部最优解

当我们去考虑两个以上的广告牌时,可以将求解的问题分解成子问题。先将只有一个广告牌的情况先计算出来,如下:total的横坐标为起始位置,纵坐标为广告牌数,计算出以某个起点到最后一个点区间的最优解。

total[0][1]=dis[0][5]=1003
total[1][1]=dis[1][5]=1000
total[2][1]=dis[2][5]=998
total[3][1]=dis[3][5]=996
total[4][1]=dis[4][5]=995
total[5][1]=dis[5][5]=0

接下来就可以一个一个去试探与剩下区间哪个区间匹配为最优解,如下

total[0][2]=dis[0][0]+total[1][1]=0+1000
total[0][2]=dis[0][1]+total[2][1]=1+998
total[0][2]=dis[0][2]+total[3][1]=2+996
total[0][2]=dis[0][3]+total[4][1]=4+995
total[0][2]=dis[0][4]+total[5][1]=6+0

可以看出放置两个广告牌的两个最优解就是[0,4][5],所以正确答案是6

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            String nums = scanner.nextLine();
            String[] numsArray = nums.split(" ");
            int[] arr = new int[100];
            int m=numsArray.length-1,n=0;
            int[][] dis = new int[100][100];
            int[][] total = new int[100][100];
            for(int i=0;i<numsArray.length;i++){
                if(numsArray.length-1==i){
                    n = Integer.valueOf(numsArray[i]);
                }else{
                    arr[i] = Integer.valueOf(numsArray[i]);
                }
            }

            for (int i = 0; i < m; i++) {
                for (int j = i; j < m; j++) {
                    for (int k = i; k <= j; k++)
                        dis[i][j] += Math.abs(arr[(i + j) / 2] - arr[k]);
                }
            }

            for (int i = 0; i < m; i++)
                total[i][1] = dis[i][m - 1];
            for (int i = 2; i <= n; i++) {
                for (int j = 0; j < m; j++) {
                    for (int k = j; k <= m-i; k++)
                        if(total[j][i] == 0) {
                            total[j][i] = dis[j][k] + total[k + 1][i - 1];
                        }else{
                            total[j][i] = Math.min(total[j][i] , dis[j][k] + total[k + 1][i - 1]);
                        }
                }
            }
            System.out.println(total[0][n]);

        }
    }
}

 

 


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值