1. 程式人生 > 其它 >密碼脫落-藍橋杯-最大公共子序列

密碼脫落-藍橋杯-最大公共子序列

https://www.acwing.com/problem/content/description/1224/

最長公共子序列問題在《演算法導論》P222頁有其原理證明。

“比對兩段DNA序列的相似度”就是一個很好的例子。

動態規劃的核心思想就是自底向上地解決遞迴中的重複子結構問題。利用空間迭代(或者說是狀態轉移)來換取遞迴的堆疊操作和時間。

純dfs解法1:33分,但其實應該是錯的,最小解應該取兩個dfs的min

#include<bits/stdc++.h>
using namespace std;

string s;
int ans;
void dfs(int i,int j,int u){
    if(i>=j)    {
        ans=u;
        return ;
    }
    if(s[i]!=s[j]){
        dfs(i+1,j,u+1);
        dfs(i,j-1,u+1);
    }else{
        dfs(i+1,j-1,u);
    }
    
    return ;
}
int main(){
    cin>>s;
    int n=s.size();
    dfs(0,n-1,0);
    cout<<ans;
    return 0;
}

純dfs解法2:正確寫法:

此題無法繼續剪枝;

#include<stdc++.h>
using namespace std;

string s;
int ans;
int  dfs(int i,int j,int u){
    if(i>=j)    {
        return u;
    }
    if(s[i]!=s[j]){
        return min(dfs(i+1,j,u+1),dfs(i,j-1,u+1));
    }else{
        return dfs(i+1,j-1,u);
    }
}
int main(){
    cin>>s;
    int n=s.size();
    cout<<dfs(0,n-1,0);
    
    return 0;
}

3.dp區間規劃:

為了方便理解我還是單獨開闢空間給逆序串來比對

優雅而快捷~

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
string s;
int dp[N][N];

int main(){
    cin>>s;
    int n=s.size();
    string s2=s;
    reverse(s2.begin(),s2.end()); //單獨開闢空間給逆序串來比對
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(s[i]==s2[j])  dp[i][j]=dp[i-1][j-1]+1;
            else    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    cout<<n-dp[n][n];
   
    return 0;
}