你得到n分p1,p2 ,. 。 。 ,pn在实线上。 pi的位置 由坐标xi给出 。您 也给出间隔I1,I2,... 。 。 ,我在哪里Ij = [aj,bj](aj是左端点,bj是右端 点)。每个间隔j具有非负权重wj。据说间隔Ij覆盖pi 如果xi∈[aj,bj]。一个 子集S⊆{I1,I2 ,. 。 。如果对于每个pi,间隔是给定点的覆盖 ,1≤i≤n,有一些 在S中的间隔涵盖pi 。在图below中,以粗体显示的间隔形成了点的覆盖。
目标是找到积分的最小重量。请注意,最小重量覆盖可能不同 从最小间隔的封面。
ps:我首先尝试找到最小的间隔,每次我们找到有效的最小间隔时,我们从P []中移除其覆盖点,直到P []为空,但这种算法很容易被证明是错误的。然后我尝试选择重量与其覆盖点数量的最小比例,但我不知道如何将其应用于带有记忆的dp。
答案 0 :(得分:2)
所以我们在这里可以做的是首先对所有p[]
数组值进行排序,并根据a[]
(即左端点)对间隔进行排序。
现在,在每个州,我们可以有两个index
,第一个是index of the interval
,第二个是index of the point
所以在每个州,我们有两个案例:
第一种情况很简单,即我们不选择当前的间隔。
在第二种情况下,我们可以做的是选择当前间隔,如果该点位于内部,还要注意,如果我们采用当前间隔,我们只能将新状态中的index of the point
向前移动我们在当前间隔中找到的点数,因为它们已被排序。
使用Recursive Dynamic Programming
的{{1}}解决方案的伪代码:
memoisation
以上内容可以轻松修改为实数。
上述代码的复杂性为#define INF 1e9
int n = 100;
int m = 100;
int p[100], a[100], b[100], w[100], memo[100][100];//initialize memo to -1
int solve(int intervalIndex, int pointIndex){
if(intervalIndex == m){
if(pointIndex == n) return 0;
else return INF;
}
if(pointIndex == n) return 0;
if(memo[intervalIndex][pointIndex] != -1) return memo[intervalIndex][pointIndex];
//we can make 2 choices either to select this interval ao not to select this interval
//if we select this interval, then we also take the points that it covers
//case #1 : do not take current interval
int ans = solve(intervalIndex + 1, pointIndex);
if(a[intervalIndex] <= p[pointIndex] && b[intervalIndex] >= p[pointIndex]){ //i.e this point is inside curr interval
//case # 2 : take current interval, and all the points it contains
int index = pointIndex;
for(int i = pointIndex + 1; i < n; i++){
if(a[intervalIndex] <= p[i] && b[i] >= p[i]){
index = i;
}else{
break;
}
}
ans = min(ans, solve(intervalIndex + 1, index + 1) + w[intervalIndex]);
}
return memo[intervalIndex][pointIndex] = ans;
}
,但如果我们只预先计算与间隔对应的最远点索引的值,则可以将其简化为O(m*n*n)
,这样我们就不会必须使用for循环来搜索它,而只是使用预先计算的值。