3-27 直线k覆盖问题
问题描述
给定一条直线L上的n个点 ,每个点 都有一个权 ,以及在该点设置服务机构的费用 。每个服务机构的覆盖半径为 r。直线 k 覆盖问题要求找出 的一个子集 , ,在点集S处设置服务机构,使总覆盖费用达到最小。
直线 L 上的每个点
是一个客户。每个点 xi 到服务机构 S 的距离定义为
。如果客户
在S的服务覆盖范围内,即
,则其服务费用为 0,否则其服务费用为
。服务机构 S 的总覆盖费用为:
式中 的定义为:
对于给定直线L上的n个点 ,编程计算在直线L上最多设置k处服务机构的最小覆盖费用。
数据输入:
第 1 行有 3 个正整数 n,k 和 r。n 表示直线 L 上有 n 个 点
; k是服务机构总数的上限; r是服务机构的覆盖半径。接下来的n行中,每行有 3 个整数。第 i+1 行的 3 个整数
分别表示
,
和
。
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