我有2D大小的数组,m*m
元素值为0s或1s。此外,数组的每一列都有一个连续的1s块(该块之外为0)。数组本身太大,无法保存在内存中(最多10 ^ 6行),但是对于每一列,我都可以确定该列中1的下限a
和上限b
。对于给定n
,我需要找出n
最大数量为1的那些连续行。对于一个较小的数字,我可以轻松地做到这一点,方法是逐行计算每一行的总和,然后选择n
总和最大的连续行,但是对于较大的数字,这会浪费太多时间。有什么有效的方法可以计算出来吗?也许使用动态编程?
这是一个示例代码片段,显示了我当前的方法,其中对的连续调用read_int()
(此处未给出)提供了连续列的上下限:
long int harr[10000]={0}; //initialized to zero
for(int i=0;i<m;i++)
{
a=read_int();
b=read_int();
for(int j=a;j<=b;j++) // for finding sum of each row
harr[j]++;
}
answer=0;
for(int i=0;i<n;i++)
{
answer=answer+harr[i];
}
current=answer;
for(int i=n;i<m;i++)
{
current=current+harr[i]-harr[i-n];
if(current>answer)
{
answer=current;
}
}
例如(具有m
= 6和n
= 3)
答案是第1到第3行,这些行中的1总数为13。(如果有平局,则第2行到第4行也会使总和最大化。)
这是另一种方法。认为每对a
,b
作为定义形式[A,B + 1)的间隔。任务是找到n
使该区间中数字的括号深度之和最大的连续索引。每一个新的a
颠簸在括号深度a
可达1。每一个新的b
原因括号深度后, b
由1下井在第一次-只要加载这些括号深度增量。然后,一遍从这些增量中获得括号深度。以下代码说明了这种方法。m
为了测试目的,我减少到了6个,并read_int()
通过访问硬连线数组(对应于问题中的示例)替换了对未知对象的调用:
#include <stdio.h>
int main(void){
int a,b,answer,current,lower,upper;
int n = 3;
int lower_bound[6] = {0,1,2,3,1,2};
int upper_bound[6] = {3,4,3,5,2,4};
int m = 6;
int harr[6]={0};
//load parenthesis depth-deltas (all initially 0)
for(int i=0;i<m;i++)
{
a = lower_bound[i];
b = upper_bound[i];
harr[a]++;
if(b < m-1)harr[b+1]--;
}
//determine p-depth at each point
for(int i = 1; i < m; i++){
harr[i] += harr[i-1];
}
//find optimal n-rows by sliding-window
answer = 0;
for(int i=0;i<n;i++)
{
answer = answer+harr[i];
}
current =answer;
lower = 0;
upper = n-1;
for(int i=n;i<m;i++)
{
current = current+harr[i]-harr[i-n];
if(current>answer)
{
answer = current;
lower = i-n+1;
upper = i;
}
}
printf("Max %d rows are %d to %d with a total sum of %d ones\n", n,lower,upper,answer);
return 0;
}
(显然,harr
可以将加载的循环与计算的循环合并answer
。我将其保留为两次,以更好地说明如何harr
从括号delta中获取最终值的逻辑)。
编译并运行此代码时,其输出为:
Max 3 rows are 1 to 3 with a total sum of 13 ones
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句