动态编程以找到点

时间:2016-03-27 02:50:52

标签: algorithm dynamic-programming

你得到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。

1 个答案:

答案 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循环来搜索它,而只是使用预先计算的值。