算法设计与分析: 3-27 直线k覆盖问题

这篇博客探讨了直线k覆盖问题,其中涉及到在给定的直线L上选取最多k个点设置服务机构,以最小化总覆盖费用。每个点具有权值和设置费用,并且每个服务机构有固定的覆盖半径r。文章提供了Java实现的两个版本,解决这个问题并解释了算法思路。

3-27 直线k覆盖问题


问题描述

给定一条直线L上的n个点x1<x2<...<xnx1<x2<...<xn,每个点xixi都有一个权w(i)0w(i)≥0,以及在该点设置服务机构的费用 c(i)0c(i)≥0 。每个服务机构的覆盖半径为 r。直线 k 覆盖问题要求找出Vn={x1,x2,...,xn}Vn={x1,x2,...,xn}的一个子集SVnS⊆Vn|S|k|S|≤k,在点集S处设置服务机构,使总覆盖费用达到最小。

直线 L 上的每个点 xixi 是一个客户。每个点 xi 到服务机构 S 的距离定义为d(i,S)=minyS{|xiy|}d(i,S)=miny∈S{|xi−y|}。如果客户xixi在S的服务覆盖范围内,即d(i,S)rd(i,S)≤r,则其服务费用为 0,否则其服务费用为 w(i)w(i) 。服务机构 S 的总覆盖费用为:

cost(S)=xiSc(i)+j=1nw(j)I(j,S)cost(S)=∑xi∈Sc(i)+∑j=1nw(j)⋅I(j,S)

式中I(j,S)I(j,S)的定义为:

I(j,S)={01d(j,S)rd(j,S)>rI(j,S)={0d(j,S)≤r1d(j,S)>r

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

数据输入:
第 1 行有 3 个正整数 n,k 和 r。n 表示直线 L 上有 n 个 点x1<x2<...<xnx1<x2<...<xn; k是服务机构总数的上限; r是服务机构的覆盖半径。接下来的n行中,每行有 3 个整数。第 i+1 行的 3 个整数 xi,wi,cixi,wi,ci 分别表示 xixi , w(i)w(i)c(i)c(i)


Java: version 1

import java.util.Scanner;

public class ZhiXianKFuGai {

    private static int n,m,r;
    private static int[] x,w,c;
    private static int[][] opt1,opt2;
    private static int MAX = 1000000;

    public static void main(String[] args){

        Scanner input = new Scanner(System.in);

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

            x = new int[n+1];
            w = new int[n+1];
            c = new int[n+1];
            opt1 = new int[m+1][n+1];
            opt2 = new int[m+1][n+1];

            for(int i=1; i<=n; i++){
                x[i] = input.nextInt();
                w[i] = input.nextInt();
                c[i] = input.nextInt();
            }

            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,h,tmp;

        for(j=1; j<=n; j++){
            h = unc(j);
            opt2[1][j] = c[j];
            for(k=1; k<=h; k++)
                opt2[1][j] += w[k];
        }

        for(j=1; j<=n; j++){
            if(j > 1)
                opt1[1][j] = w[j] + opt1[1][j-1];
            else
                opt1[1][j] = MAX;
            h = cov(j);
            tmp = MAX;
            for(k=h; k<=j; k++)
                if(opt2[1][k] < tmp)
                    tmp = opt2[1][k];
            if(opt1[1][j] > tmp)
                opt1[1][j] = tmp;
        }

        for(i=2; i<=m; i++){
            for(j=i; j<=n; j++){
                h = unc(j);
                if(h < i-1)
                    h = i - 1;
                opt2[i][j] = MAX;
                for(k=h; k<j; k++){
                    tmp = opt1[i-1][k];
                    if(opt2[i][j] > tmp)
                        opt2[i][j] = tmp;
                }
                opt2[i][j] += c[j];
            }
            for(j=i; j<=n; j++){
                h = cov(j);
                if(h < i)
                    h = i;
                tmp = MAX;
                if(j > i)
                    opt1[i][j] = w[j] + opt1[i][j-1];
                else
                    opt1[i][j] = MAX;
                for(k=h; k<=j; k++)
                    if(opt2[i][k] < tmp)
                        tmp = opt2[i][k];
                if(opt1[i][j] > tmp)
                    opt1[i][j] = tmp;
            }
        }
    }

    private static int cov(int j){
        int i;
        for(i=j; i>0; i--)
            if(x[j]-x[i] > r)
                break;

        return i+1;
    }

    private static int unc(int j){
        int i;
        for(i=1; i<=j; i++)
            if(x[j]-x[i] <= r)
                break;

        return i-1;
    }
}

Java: version 2

import java.util.Scanner;

public class ZhiXianKFuGai1 {

    private static int n,m,r;
    private static int[] x,w,c;
    private static int[] opt1,opt2;
    private static int MAX = 1000000;
    private static int min;

    public static void main(String[] args){

        Scanner input = new Scanner(System.in);

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

            x = new int[n+1];
            w = new int[n+1];
            c = new int[n+1];
            opt1 = new int[n+1];
            opt2 = new int[n+1];

            for(int i=1; i<=n; i++){
                x[i] = input.nextInt();
                w[i] = input.nextInt();
                c[i] = input.nextInt();
            }

            comp();

            System.out.println(min);
        }
    }

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

        for(j=1; j<=n; j++){
            h = unc(j);
            opt2[j] = c[j];
            for(k=1; k<=h; k++)
                opt2[j] += w[k];
        }

        for(j=1; j<=n; j++){
            if(j > 1)
                opt1[j] = w[j] + opt1[j-1];
            else
                opt1[j] = MAX;
            h = cov(j);
            tmp = MAX;
            for(k=h; k<=j; k++)
                if(opt2[k] < tmp)
                    tmp = opt2[k];
            if(opt1[j] > tmp)
                opt1[j] = tmp;
        }

        min = opt1[n];

        for(i=2; i<=m; i++){
            for(j=i; j<=n; j++){
                h = unc(j);
                if(h < i-1)
                    h = i - 1;
                opt2[j] = MAX;
                for(k=h; k<j; k++){
                    tmp = opt1[k];
                    if(opt2[j] > tmp)
                        opt2[j] = tmp;
                }
                opt2[j] += c[j];
            }
            for(j=i; j<=n; j++){
                h = cov(j);
                if(h < i)
                    h = i;
                tmp = MAX;
                if(j > i)
                    opt1[j] = w[j] + opt1[j-1];
                else
                    opt1[j] = MAX;
                for(k=h; k<=j; k++)
                    if(opt2[k] < tmp)
                        tmp = opt2[k];
                if(opt1[j] > tmp)
                    opt1[j] = tmp;
            }
            if(opt1[n] < min)
                min = opt1[n];
        }
    }

    private static int cov(int j){
        int i;
        for(i=j; i>0; i--)
            if(x[j]-x[i] > r)
                break;

        return i+1;
    }

    private static int unc(int j){
        int i;
        for(i=1; i<=j; i++)
            if(x[j]-x[i] <= r)
                break;

        return i-1;
    }
}

Input & Output

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

Reference

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值