出處
幫我稍微理解了這個思想。
哎~我就是傳說中的無腦兒啊!
乙個序列x,乙個序列y,
x的下標用i,y的下標用j,
xi表示從第乙個元素到第i個元素的這個序列。
yj表示從第乙個元素到第j個元素的序列。
xi表示x序列的第i個元素,yj表示y序列的第j個元素。
我們把序列xn和ym的最長公共子串行的長度表示為f(n,m)。
先說一下遞迴的做法。
假設現在我們想要求f(i,j),
1.如果xi==yj,那麼這個xi(或者是yj)一定是xi和yj的最長公共子串行的結尾數字,好,繼續往下遞迴求x(i-1)和y(j-1)的最長公共子串行長度,長度加1就是f(i,j)的值。
2.如果xi!=yj,那麼這個 xi 一定不是xi和yj的最長公共子串行的結尾數字,那麼結尾的數字在前面,也就是f(i,j)與f(i-1,j)或者與f(i,j-1)相比長度並沒有增加,那麼我想要他們中最大的啊,於是f(i,j)=max( f(i-1,j),f(i,j-1))。好,那麼遞迴求f(i-1,j)和f(i,j-1)的值。
(你想要的最終結果就把i換成x的長度,j換成y的長度就是了)
處理一下邊界。
那顯然就是i==0或者j==0的時候了。f(0,j)或者f(i,0)都是0(這個是顯然的吧~你乙個什麼都沒有的序列和任意序列的公共子串行顯然是0啊),這樣可以返回值了。
我用偽**寫一下啊(其實也不算偽**……)
這個的前提是你已經讀入了x這個序列和y這個序列了啊。
xi表示x序列的第i個元素,yj表示y序列的第j個元素。
想求f(i,j):
if( xi==yj ) return f(i-1,j-1)+1;
else return max ( f(i-1,j) , f(i,j-1) ); /*也就是xi!=yj的時候*/
ok,那麼我們發現有很多時候有些值是重複計算的。處理方法顯然有兩種啦,一種是記憶化搜尋,一種是動態規劃了(倒著這個過程來唄)。
其實網上還有很多大牛,我就不囉嗦那些名詞了,什麼子問題重複什麼的……我只是理解而已,想讓我一板一眼地講出來還是真有難度,想知道具體的可以看他們更加專業化的講解。
我只說動態規劃的。
既然後面的狀態需要求出前面的狀態,那我何不從前面的狀態開始求起,遞推出後面的狀態呢?
初始的狀態是f(i,0)=0而且f(0,j)=0;
那麼遞推開始了,關鍵的條件還是不變的。
現在我們想求f(i,j)(它可以由前面的狀態推出來哦!注意現在是遞迴過程的逆著來了,遞迴是去找前面的狀態,動態規劃是從底層的狀態推出來高層的狀態)
if(xi==yj) f(i,j) = f ( i-1 , j-1 ) + 1;
else f(i,j)=( f(i-1,j) , f(i,j-1));
那麼一路遞推下去,推到兩個序列的長度即可。
因為f有兩個引數,所以在用**實現的時候要用二維陣列來實現。這裡我用了dp陣列來表示f這個函式。
好啦終於可以上**啦。
注意下標的處理。
ac**
#include#include#include#includeusing namespace std;
const int maxn=1e3+10;
const int inf=1e9+10;
int dp[maxn][maxn];
int main()
{
//初始化f(i,0)或者f(0,j)為0;
memset(dp,0,sizeof(dp));
char str1[maxn];
char str2[maxn];
scanf("%s %s",str1,str2);
int len1=strlen(str1);
//cout<
希望這次南寧的邀請賽能拿個獎。
動態規劃經典 最長公共子串行
最長公共子串行 時間限制 3000 ms 記憶體限制 65535 kb 難度 3 描述 咱們就不拐彎抹角了,如題,需要你做的就是寫乙個程式,得出最長公共子串行。tip 最長公共子串行也稱作最長公共子串 不要求連續 英文縮寫為lcs longest common subsequence 其定義是,乙個...
動態規劃 最長公共子串行
問題描述 我們稱序列z z1,z2,zk 是序列x x1,x2,xm 的子串行當且僅當存在嚴格上公升的序列 i1,i2,ik 使得對j 1,2,k,有xij zj。比如z a,b,f,c 是x a,b,c,f,b,c 的子串行。現在給出兩個序列x和y,你的任務是找到x和y的最大公共子串行,也就是說要...
動態規劃 最長公共子串行
兩個序列的最長公共子序 lcs longest common length 的 每個字元可以不連續,如x y 那麼它們的最長公共子串行為。這是乙個經典的動態規劃問題,著手點還是找到 最精髓的 狀態轉移方程 假設x,y兩個序列的前i,j個位置的最大子串行已經找到為r i j 自底往上 那麼x i 與y...