STテーブルはRMQ動的プログラミングのアイデアを実現します

問題の発生時に間隔の最大値または最小値を頻繁に照会する場合は非常に時間がかかりますが、stテーブル(dp配列)を前処理する場合は、一定の時間を使用して間隔の最大値照会できます

STテーブルステータスの定義

dp[i][j]間隔の左端点としてi添え字を持つ2つのj要素を含む間隔の最大要素の値を表します

すなわち、dp[i][j]=間隔[i, i+2^j-1]値が最大の要素であります

この定義の利点は、間隔の左端点の場合、費やすO(log(n))時間左端点と長さが2の累乗である間隔の最大要素を列挙できることです。

STテーブルの状態遷移

分割統治という考え方を採用しています。ある間隔の最大値を照会してその間隔を2つに分割したい場合、最大値は左半分または右半分に存在し、結果は最大になります。

同様に、我々が得られたとし、すべての [私は左点の範囲添字を、2含有J-1の最大要素間隔値要素]を、我々は問題をマージすることができます。

2 j-1の長さの区間が見つかったので、マージされた区間の長さは2 jなので、状態遷移は簡単に推測できます(最大値を見つけることを前提としています)。

dp[i][j] = max(dp[i][j-1], dp[i+2^(j-1)][j-1])

左のセクションは[lは左の端点で長さは2 j-1です ]
右のセクションは[l + 2 j-1は左の端点で長さが2 j-1です ]

2 j = 2 j-1 + 2 j-1なので2つのサブ問題は元の問題をカバーするだけなので、長さの反復の単位として2の累乗を使用する必要があります

STテーブルクエリ

任意の点の開始点と長さが2のべき乗である区間の最大値だけがわかっている場合、入力区間の長さが2のべき乗でない場合はどうなるでしょうか。

ただし、関西がない場合、任意の長さの間隔は常に2のべき乗の2つのサブインターバルに分解できます(2つのサブインターバルがわずかにオーバーラップしても、オーバーラップは最終的な問題の解決に影響しません)

  • 長さがlen = 14であるとすると、最大パワー長はsublen = 2 ^ log(2、len)= 8になります。
  • 左部分間隔は[左端点、sublen-1]で、答え1は dp[left][log(2, len)]
  • 正しい部分間隔は[右端点-sublen + 1、右端点]で、答えは dp[right-sublen+1][sublen]

ここに画像の説明を挿入

int rmq(int l, int r)
{
	if(l==r) return dp[l][0];
	int len=(r-l+1), lg=log2(len), sublen=pow2(lg);
	return max(dp[l][lg], dp[r-sublen+1][lg]);
}

コード

#include <bits/stdc++.h>

using namespace std;

#define maxn 1000
int dp[maxn][20], a[maxn], n;

int pow2(int x) {return 1<<x;}
int log2(int x) {return log((double)x)/log(2.0);}

int rmq(int l, int r)
{
	if(l==r) return dp[l][0];
	int len=(r-l+1), lg=log2(len), sublen=pow2(lg);
	return max(dp[l][lg], dp[r-sublen+1][lg]);
}

int main()
{	
	// 读取数据,dp数组初始化,长度为 2^0=1 的区间最大值就是单个元素 
	cin>>n;
	for(int i=0; i<n; i++) 
		cin>>a[i], dp[i][0]=a[i];
		
	// dp递推,因为dp[i][j] 基于所有的dp[][j-1],所以外循环是j递增 
	for(int j=1; pow2(j)<=n; j++)
		for(int i=0; i+pow2(j-1)<n; i++) 
			dp[i][j] = max(dp[i][j-1], dp[i+pow2(j-1)][j-1]);
	
	// 暴力法,RMQ查询,验证正确性 
	for(int i=0; i<n; i++)
		for(int j=i; j<n; j++)
			cout<<"["<<i<<","<<j<<"] "<<a[max_element(a+i, a+j+1)-a]<<" "<<rmq(i, j)<<endl;
	
	return 0;
}

/*
7
0 4 7 1 3 2 8
*/

出力:

7
0 4 7 1 3 2 8
[0,0] 0 0
[0,1] 4 4
[0,2] 7 7
[0,3] 7 7
[0,4] 7 7
[0,5] 7 7
[0,6] 8 8
[1,1] 4 4
[1,2] 7 7
[1,3] 7 7
[1,4] 7 7
[1,5] 7 7
[1,6] 8 8
[2,2] 7 7
[2,3] 7 7
[2,4] 7 7
[2,5] 7 7
[2,6] 8 8
[3,3] 1 1
[3,4] 3 3
[3,5] 3 3
[3,6] 8 8
[4,4] 3 3
[4,5] 3 3
[4,6] 8 8
[5,5] 2 2
[5,6] 8 8
[6,6] 8 8
公開された262元の記事 ウォン称賛11 ビュー10000 +

おすすめ

転載: blog.csdn.net/weixin_44176696/article/details/105178155