算法设计与分析: 3-26 直线k中值问题

3-26 直线k中值问题


问题描述

在一个按照南北方向划分成规整街区的城市里,n 个居民点分布在一条直线上的 n 个坐标点 x1<x2<...<xn x 1 < x 2 < . . . < x n 处。居民们希望在城市中至少选择1个,但不超过k个居民点建立服务机构。在每个居民点 xi x i 处,服务需求量为 wi>=0 w i >= 0 ,在该居民点设置服务机构的费用为 ci>=0 c i >= 0 。 假设居民点 xi x i 到距其最近的服务机构的距离为 di d i ,则居民点xi的服务费用为 wi×di w i × d i

建立 k 个服务机构的总费用为 A+B。A 是在 k 个居民点设置服务机构的费用的总和;B 是 n 个居民点服务费用的总和。

对于给定直线L上的n个点 x1<x2<...<xn x 1 < x 2 < . . . < x n ,编程计算在直线L上最多设置k处服务机构的最小总费用。

数据输入:
第 1 行有 2 个正整数 n 和 k。n 表示直线 L 上有 n 个点 x1<x2<...<xn x 1 < x 2 < . . . < x n ; k是服务机构总数的上限。接下来的n行中,每行有3个整数。第i+1行的3个整数 xi x i , wi w i , ci c i ,分别表示相应居民点的位置坐标,服务需求量和在该点设置服务机构的费用。


Java: version 1

import java.util.Scanner;

public class ZhiXianKZhongZhi {

    private static int n,m;
    private static int[] wt,swt,x,c,ww,dist;
    private static int[][] opt1,opt2;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int w;

        while (true){
            n = input.nextInt();
            m = input.nextInt();

            wt = new int[n+1];
            swt = new int[n+1];
            x = new int[n+1];
            c = new int[n+1];
            ww = new int[n+1];
            dist = new int[n+1];
            opt1 = new int[m+1][n+1];
            opt2 = new int[m+1][n+1];

            wt[0] = 0;
            swt[0] = 0;

            for(int i=1; i<=n; i++){
                x[i] = input.nextInt();
                w = input.nextInt();
                c[i] = input.nextInt();
                ww[i] = w;
                wt[i] = wt[i-1] + w;
                dist[i] = x[i] - x[1];
                swt[i] = swt[i-1] + w * dist[i];
            }

            comp();
            System.out.println(solution());
        }
    }

    private static int solution(){
        int tmp = opt1[1][n];
        for(int i=2; i<=m; i++)
            if(opt1[i][n] < tmp)
                tmp = opt1[i][n];

        return tmp;
    }

    private static void comp(){
        int i,j,k,tmp;

        for(j=1; j<=n; j++)
            opt2[1][j] = c[j] + getw2(0,j);

        for(j=1; j<=n; j++) {
            opt1[1][j] = opt2[1][1] + getw1(1,j);
            for(k=2; k<=j; k++){
                tmp = opt2[1][k] + getw1(k,j);
                if(opt1[1][j] > tmp)
                    opt1[1][j] = tmp;
            }
        }

        for(i=2; i<=m; i++){
            for(j=i; j<=n; j++){
                opt2[i][j] = opt1[i-1][i-1] + getw2(i-1,j);
                for(k=i; k1][k] + getw2(k,j);
                    if(opt2[i][j] > tmp)
                        opt2[i][j] = tmp;
                }
                opt2[i][j] += c[j];
            }

            for(j=i; j<=n; j++){
                opt1[i][j] = opt2[i][i] + getw1(i,j);
                for(k=i+1; k<=j; k++){
                    tmp = opt2[i][k] + getw1(k,j);
                    if(opt1[i][j] > tmp)
                        opt1[i][j] = tmp;
                }
            }
        }
    }

    private static int getw1(int j, int m){
        return (swt[m] - swt[j]) - (wt[m] - wt[j]) * dist[j];
    }

    private static int getw2(int j, int m){
        return (wt[m-1] - wt[j]) * dist[m] - (swt[m-1] - swt[j]);
    }
}

Java: version 2

import java.util.Scanner;

public class ZhiXianKZhongZhi1 {

    private static int n,m;
    private static int[] wt,swt,x,c,ww,dist;
    private static int[] opt1,opt2;
    private static int min;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int w;

        while (true){
            n = input.nextInt();
            m = input.nextInt();

            wt = new int[n+1];
            swt = new int[n+1];
            x = new int[n+1];
            c = new int[n+1];
            ww = new int[n+1];
            dist = new int[n+1];
            opt1 = new int[n+1];
            opt2 = new int[n+1];

            wt[0] = 0;
            swt[0] = 0;

            for(int i=1; i<=n; i++){
                x[i] = input.nextInt();
                w = input.nextInt();
                c[i] = input.nextInt();
                ww[i] = w;
                wt[i] = wt[i-1] + w;
                dist[i] = x[i] - x[1];
                swt[i] = swt[i-1] + w * dist[i];
            }

            comp();
            System.out.println(min);
        }
    }

    private static void comp(){
        int i,j,k,tmp;

        for(j=1; j<=n; j++)
            opt2[j] = c[j] + getw2(0,j);

        for(j=1; j<=n; j++) {
            opt1[j] = opt2[1] + getw1(1,j);
            for(k=2; k<=j; k++){
                tmp = opt2[k] + getw1(k,j);
                if(opt1[j] > tmp)
                    opt1[j] = tmp;
            }
        }

        min = opt1[n];

        for(i=2; i<=m; i++){
            for(j=i; j<=n; j++){
                opt2[j] = opt1[i-1] + getw2(i-1,j);
                for(k=i; kif(opt2[j] > tmp)
                        opt2[j] = tmp;
                }
                opt2[j] += c[j];
            }

            for(j=i; j<=n; j++){
                opt1[j] = opt2[i] + getw1(i,j);
                for(k=i+1; k<=j; k++){
                    tmp = opt2[k] + getw1(k,j);
                    if(opt1[j] > tmp)
                        opt1[j] = tmp;
                }
            }

            if(opt1[n] < min)
                min = opt1[n];
        }
    }

    private static int getw1(int j, int m){
        return (swt[m] - swt[j]) - (wt[m] - wt[j]) * dist[j];
    }

    private static int getw2(int j, int m){
        return (wt[m-1] - wt[j]) * dist[m] - (swt[m-1] - swt[j]);
    }
}

Input & Output

9 3
2 1 2
3 2 1
6 3 3
7 1 1
9 3 2
15 1 6
16 2 1
18 1 2
19 1 1
19

Reference

王晓东《计算机算法设计与分析》(第3版)P99-100

你可能感兴趣的:(直线k中值问题,动态规划,算法,Java,Algorithm,Java,动态规划,计算机算法设计与分析,计算机算法设计与分析)