从特定的广告牌中删除广告牌

时间:2012-02-21 11:41:44

标签: algorithm

我遇到了这个问题

  

ADZEN是您所在城市非常受欢迎的广告公司。在每一条路上   你可以看到他们的广告牌。最近他们面临着一个问题   严峻的挑战,MG道路中最常用,最美丽的道路   城市几乎被广告牌所填满,这是一个   对...的负面影响       自然观。           根据人们的需求,ADZEN决定拆除一些广告牌        以这种方式,只有K个广告牌站在一起       在任何一条路上。           你可以假设MG Road是一条带有N个广告牌的直线。最初两个adjecent之间没有差距   广告牌。           ADZEN的主要收入来自这些广告牌,因此广告牌移除过程必须以这样的方式完成   广告牌       保留在最后应该在所有可能的最终配置中给出最大可能的利润。配置的总利润是   所有广告牌的利润价值总和   组态。           给定N,K和N个广告牌中的每一个的利润值,输出可以从剩余的广告牌中获得的最大利润   在给定条件下的广告牌。

     

输入说明

     

第1行包含两个空格分隔的整数N和K.然后按N行描述每个广告牌的利润值,即ith   line包含第i个广告牌的利润值。

    Sample Input
    6 2 
    1
    2
    3
    1
    6
    10 

    Sample Output
    21
     

解释

     

在给定的输入中有6个广告牌,在此过程之后不应超过2个。所以删除第1和第4   给出配置的广告牌_2 3 _ 6 10,利润为21。   没有其他配置的利润超过21.所以答案是21。

    Constraints
    1 <= N <= 1,00,000(10^5)
    1 <= K <= N
    0 <= profit value of any billboard <= 2,000,000,000(2*10^9)

我认为我们必须在第一个k + 1板上选择最低成本板,然后重复相同的直到最后,但这没有给出正确的答案 对于所有情况。 我尝试了我的知识,但无法找到解决方案。         如果有人有想法,请分享你的想法。

7 个答案:

答案 0 :(得分:12)

这是典型的DP问题。让我们说P(n,k)是将k个广告牌放到道路上的位置n的最大利润。然后你有以下公式:

 P(n,k) = max(P(n-1,k), P(n-1,k-1) + C(n))
 P(i,0) = 0 for i = 0..n

其中c(n)是将第n个广告牌放在路上的利润。使用该公式计算P(n,k)自下而上,你将在O(nk)时间内得到解决方案。

我会留意你找出为什么这个公式成立。

修改

方,我误解了这个问题。

它仍然是DP问题,只是公式不同。假设P(v,i)表示最后一组广告牌的大小为i的点v的最大利润。 然后可以使用以下公式描述P(v,i):

P(v,i) = P(v-1,i-1) + C(v) if i > 0 
P(v,0) = max(P(v-1,i) for i = 0..min(k, v)) 
P(0,0) = 0

您需要找到max(P(n,i) for i = 0..k))

答案 1 :(得分:1)

此问题是www.interviewstreet.com上发布的挑战之一...

我很高兴地说我最近得到了这个,但不太满意,想看看那里是否有更好的方法。

灵魂检查上面的DP解决方案很简单,但由于K可以和N一样大,所以无法完全解决这个问题,这意味着DP复杂度对于运行时和空间都是O(NK)。 / p>

另一个解决方案是进行分支绑定,跟踪到目前为止的最佳总和,并在某个级别修剪递归,也就是说,如果currSumSoFar + SUM(a [currIndex..n))&lt; = bestSumSoFar ...然后立即退出函数,当上限到目前为止不会超过最佳总和时,没有进一步处理的点。

除了2个测试用例之外,测试人员都接受了上面的分支绑定。 幸运的是,我注意到2个测试用例使用小K(在我的情况下,K <300),因此O(NK)的DP技术就足够了。

答案 2 :(得分:1)

soulcheck(第二)DP解决方案原则上是正确的。您可以使用这些观察结果进行两项改进:

1)不必分配整个DP表。你一次只能看两行。

2)对于每一行(P(v,i)中的v),您只对最大增加最大值的i感兴趣,这比在前一行中保持最大值的每个i多一个。此外,i = 1,否则你永远不会考虑空白。

答案 3 :(得分:1)

我使用DP in O(nlogk)在c ++中编码。 想法是为给定位置维持具有下一个k值的多集。该多集合通常在中间处理中具有k值。每次移动元素并推送新元素。艺术是如何保持这个列表有利润[i] +回答[i + 2]。关于集合的更多细节:



/*
 * Observation 1: ith state depends on next k states i+2....i+2+k
 * We maximize across this states added on them "accumulative" sum
 *
 * Let Say we have list of numbers of state i+1, that is list of {profit + state solution}, How to get states if ith solution
 *
 * Say we have following data k = 3
 *
 * Indices:     0   1   2   3   4
 * Profits:     1   3   2   4   2
 * Solution:    ?   ?   5   3   1
 *
 * Answer for [1] = max(3+3, 5+1, 9+0) = 9
 *
 * Indices:     0   1   2   3   4
 * Profits:     1   3   2   4   2
 * Solution:    ?   9   5   3   1
 *
 * Let's find answer for [0], using set of [1].
 *
 * First, last entry should be removed. then we have (3+3, 5+1)
 *
 * Now we should add 1+5, but entries should be incremented with 1
 *      (1+5, 4+3, 6+1) -> then find max.
 *
 *  Could we do it in other way but instead of processing list. Yes, we simply add 1 to all elements
 *
 *  answer is same as: 1 + max(1-1+5, 3+3, 5+1)
 *
 */

ll dp()
{
multiset<ll, greater<ll> > set;

mem[n-1] = profit[n-1];

ll sumSoFar = 0;

lpd(i, n-2, 0)
{
    if(sz(set) == k)
        set.erase(set.find(added[i+k]));

    if(i+2 < n)
    {
        added[i] = mem[i+2] - sumSoFar;
        set.insert(added[i]);
        sumSoFar += profit[i];
    }

    if(n-i <= k)
        mem[i] = profit[i] + mem[i+1];
    else 
        mem[i] = max(mem[i+1], *set.begin()+sumSoFar);
}

return mem[0];
 }

答案 4 :(得分:0)

这看起来像是线性编程问题。这个问题是线性的,但是要求不超过K个相邻的广告牌可能会保留。

有关一般治疗,请参阅维基百科:http://en.wikipedia.org/wiki/Linear_programming

访问您的大学图书馆,找到有关该主题的优秀教科书。

有许多库可以帮助进行线性编程,因此我建议您不要尝试从头开始编写算法。以下是与Python相关的列表:http://wiki.python.org/moin/NumericAndScientific/Libraries

答案 5 :(得分:0)

如果我们删除广告牌P[i],则1..i(其中i = 1..n)是广告牌i的最大利润。知道所有P [i],计算答案是微不足道的。计算P [i]的基线算法如下:

for i=1,N
{
  P[i]=-infinity;
  for j = max(1,i-k-1)..i-1
  {
    P[i] = max( P[i], P[j] + C[j+1]+..+C[i-1] );
  }
}

现在这个想法可以让我们加快速度。我们假设我们只有两种不同的有效配置广告牌1i,让我们将这些配置称为X1X2。如果在配置iX1中移除了广告牌profit(X1) >= profit(X2),那么我们应该始终更喜欢配置X1广告牌1..iprofit()我的意思是仅从广告牌1..i中获利,无论i+1..n的配置如何)。这很重要,显而易见。


我们引入了一个双重链接的元组列表{idx,d}{{idx1,d1}, {idx2,d2}, ..., {idxN,dN}}

  • p->idx是删除的最后一个广告牌的索引。我们通过列表时p->idx正在增加:p->idx < p->next->idx
  • 如果p->d不是列表中的最后一个元素,则
  • (C[p->idx]+C[p->idx+1]+..+C[p->next->idx-1])是元素p的总和。否则,它是直到当前位置的元素总和减1:(C[p->idx]+C[p->idx+1]+..+C[i-1])

以下是算法:


P[1] = 0;
list.AddToEnd( {idx=0, d=C[0]} );
// sum of elements starting from the index at top of the list
sum = C[0]; // C[list->begin()->idx]+C[list->begin()->idx+1]+...+C[i-1]
for i=2..N
{
  if( i - list->begin()->idx > k + 1 ) // the head of the list is "too far"
  {
    sum = sum - list->begin()->d
    list.RemoveNodeFromBeginning()
  }
  // At this point the list should containt at least the element
  // added on the previous iteration. Calculating P[i].
  P[i] = P[list.begin()->idx] + sum
  // Updating list.end()->d and removing "unnecessary nodes"
  // based on the criterion described above
  list.end()->d = list.end()->d + C[i]
  while(
    (list is not empty) AND
    (P[i] >= P[list.end()->idx] + list.end()->d - C[list.end()->idx]) )
  {
    if( list.size() > 1 )
    {
      list.end()->prev->d += list.end()->d
    }
    list.RemoveNodeFromEnd();
  }
  list.AddToEnd( {idx=i, d=C[i]} );
  sum = sum + C[i]
}

答案 6 :(得分:0)

//shivi..coding is adictive!!
#include<stdio.h>

long long int arr[100001];
long long  int sum[100001];
long long  int including[100001],excluding[100001];
long long int maxim(long long int a,long long int b)
{if(a>b) return a;return b;}

int main()
{
int N,K;
scanf("%d%d",&N,&K);
for(int i=0;i<N;++i)scanf("%lld",&arr[i]);

sum[0]=arr[0];
including[0]=sum[0];
excluding[0]=sum[0];
for(int i=1;i<K;++i)
{
    sum[i]+=sum[i-1]+arr[i];
    including[i]=sum[i];
    excluding[i]=sum[i];
}

long long int maxi=0,temp=0;
for(int i=K;i<N;++i)
{
    sum[i]+=sum[i-1]+arr[i];
    for(int j=1;j<=K;++j)
    {
        temp=sum[i]-sum[i-j];
        if(i-j-1>=0)
        temp+=including[i-j-1];
        if(temp>maxi)maxi=temp;
    }
    including[i]=maxi;
    excluding[i]=including[i-1];
}
printf("%lld",maxim(including[N-1],excluding[N-1]));
}

//here is the code...passing all but 1 test case :) comment improvements...simple DP