動的計画法01-LIS、LCS、デジタルトライアングル

LIS:最長の昇順部分列問題

境界処理:f [0] = 0;

方法1:f [i]からどの状態を導き出すことができるかを検討します

for(int i = 0; i < n; i++)  i:结尾下标
	for(int j = i + 1; j <= n; j++) 下一个数
		if(a[j] > a[i]) f[j]=max(f[j],f[i]+1);

方法2:どの状態からf [i]を取得できるかを検討します。
この方法はより一般的に使用されます。

for(int i = 1; i <= n; i++)
	for(int j = 0;j < i;j++) 前一个数 
		if(a[j] < a[i]) f[i]=max(f[i],f[j]+1); 

目的

 for(int i=1;i<=n;i++) ans=max(ans,f[i]);

最適な解決策は何ですか?

	for(int i=1;i<=n;i++)
	{
    
    
		for(int j=0;j<i;j++)
		{
    
    
			if(a[j]>a[i])
				if(f[j]+1>f[i]){
    
    
					f[i]=f[j]+1;
					pos[i]=j;//记录由某点推导过来的该点的下标 
				}
		}
	}
	void print(int i)
	{
    
    
		if(i==0) return ;
		print(pos[i]);//递归处理 
		cout<<a[i]<<" ";
		 
	}
	
	int ans=0,tail;
	for(int i=1;i<=n;i++)
		if(f[i]>ans) ans=f[i],tail=i;
	cout<<ans<<endl;
	print(tail);

二分最適化

q [i] q [i] q [ i ]は、長さiの昇順サブシーケンスの最後の番号、列挙されたシーケンスa [i] a [i]の番号を表します。a [ i ]qqに入れますq配列最大値は、[i] a [i]未満です多くの後、[ I ]、それは二分法により実現されます。時間計算量nlognnlognN L O G N

    for(int i=1;i<=n;i++) cin>>a[i];
    int len=0;
    for(int i=1;i<=n;i++)
    {
    
    
        int l=0,r=len;
        while(l<r)
        {
    
    
            int mid=(l+r+1)>>1;
            if(q[mid]<a[i]) l=mid;
            else r=mid-1;
        }
        len=max(len,r+1);
        q[r+1]=a[i];
    }
    cout<<len;

LCS:最長共通部分列問題

ボーダー処理

for(int i = 0; i <= n; i++) f[i][0]=0;
for(int j = 0; j <= m; j++) f[0][j]=0;

状態遷移

for(int i = 1;i <= n;i++)
	for(int j=1; j<= m ;j++)
		f[i][j]=max(f[i-1][j],f[i][j-1]);
		if(a[i] == a[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);

目的

cout<<f[n][m]<<endl;

デジタルトライアングルモデル

アイデア
現在の座標(i、j)は(i + 1、j)(i + 1、j + 1)に移動できます

境界処理

f[1][1]=a[1][1]

状態遷移

for(int i = 1;i<n;i++)
    for(int j=1;j<=i;j++){
    
    
        f[i+1][j]=max(f[i+1][j],f[i][j]+a[i+1][j]);
        f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+a[i+1][j+1]);
    }

目標結果

int ans=0;
for(int j=1;j<=n;j++)
    ans=max(ans,f[n][j]);

おすすめ

転載: blog.csdn.net/qq_45327808/article/details/109755404