1. 程式人生 > >倍增RMQ演算法淺談

倍增RMQ演算法淺談

題目:

求某一區間的最大值。

 

f[a][b]中a代表的是當前的位置,b代表的是以a為起點往後移動的區間長度2^b。

 1 void bz(int n)
 2 {
 3     for(int i=1;i<=n;i++)
 4         f[i][0]=a[i];//先定義長度1為自己本身。
 5     for(int j=1;(1<<j)<=n;j++)//以區間逐步移長。//tip1
 6     {
 7         for(int i=1;i+(1<<j)-1<=n;i++)//點的位置逐步往後移。//tip2
 8           f[i][j]=max(f[i][j-1
],f[i+(1<<(j-1))][j-1]); 9 } 10 }

其實tip1與tip2是利用以小的區間的最大值來逐步往上推更大的區間的最值。具體怎麼推呢就需要利用到倍增思想(其實跟二分很相似)。

我們來模擬一下吧!

f[1][1]=max(f[1][0],f[2][0]);f[1][2]=max(f[1][1],f[3][1]);

f[1][1]={1,2},f[1][0]={1},f[2][0]={2},f[1][2]={1,2,3,4},f[3][1]={3,4};//大括號裡面代表的是位置。

因此可以看出要求f[1][1]就直接看1位置與2位置的最值,f[1][2]是由f[1][1]與f[3][1]比較得出的。在這裡也體現了由小區來推廣到大區間,因為所求的大區間都可以通過二進位制關係分為兩個小區間問題(若重疊也是沒關係的),而最小的問題也就是最初定義f[a][0]為a位置本身的問題;

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn=1e3+7;
 7 int num[maxn],f[1000][1000];
 8 int main()
 9 {
10     int n,a,b,c,d,q,l,r;
11     while(~scanf("%d",&n))
12     {
13         for(int i=1;i<=n;i++)
14 { 15 scanf("%d",&num[i]); 16 } 17 for(int i=1;i<=n;i++) 18 { 19 f[i][0]=num[i]; 20 } 21 for(int i=1;i<20;i++) 22 { 23 for(int j=1;j+(1<<(i-1))-1<=n;j++) 24 { 25 f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]); 26 } 27 } 28 cin>>q; 29 for(int i=1;i<=q;i++) 30 { 31 cin>>l>>r; 32 int k=(int)(log(r-l+1.0)/log(2.0)); 33 printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k])); 34 } 35 } 36 }