Jednym względnie prostym sposobem byłoby zrekonstruowanie sekwencji z macierzy LCS. Oto algorytm O (n^2 * k + x * n), w którym to przypadku, gdzie x jest wielkością wyjściową (to jest liczbą wspólnych podsekwencji o długości k). To jest w C++, ale powinno być raczej łatwo przetłumaczyć na C:
const int N = 100;
int lcs[N][N];
set<tuple<string,int,int,int>> vis;
string s1 = "AAGACC";
string s2 = "AGATAACCAGGAGCTGC";
void reconstruct(const string& res, int i, int j, int k) {
tuple<string,int,int,int> st(res, i, j, k);
if (vis.count(st))
return;
vis.insert(st);
if (lcs[i][j] < k) return;
if (i == 0 && j == 0 && k == 0) {
cout << res << endl;
return;
}
if (i > 0)
reconstruct(res, i-1, j, k);
if (j > 0)
reconstruct(res, i, j-1, k);
if (i>0 && j>0 && s1[i-1] == s2[j-1])
reconstruct(string(1,s1[i-1]) + res, i-1, j-1, k-1);
}
int main() {
lcs[0][0] = 0;
for (int i = 0; i <= s1.size(); ++i)
lcs[i][0] = 0;
for (int j = 0; j <= s1.size(); ++j)
lcs[0][j] = 0;
for (int i = 0; i <= s1.size(); ++i) {
for (int j = 0; j <= s2.size(); ++j) {
if (i > 0)
lcs[i][j] = max(lcs[i][j], lcs[i-1][j]);
if (j > 0)
lcs[i][j] = max(lcs[i][j], lcs[i][j-1]);
if (i > 0 && j > 0 && s1[i-1] == s2[j-1])
lcs[i][j] = max(lcs[i][j], lcs[i-1][j-1] + 1);
}
}
reconstruct("", s1.size(), s2.size(), 5);
}
Nie powinno być także O (n * (k + x)) sposobem rozwiązania tego w oparciu o nieco innym podejściu DP: Niech f (i, k) będzie minimalnym indeksem j takim, że lcs (i, j)> = k. Mamy nawrotowi
f(i, 0) = 0 for all i
f(i, k) = min{f(i-1, k),
minimum j > f(i-1, k-1) such that s2[j] = s1[i]}
może również zrekonstruować sekwencje długości K z matrycy F.
OP, jesteś zaznajomiony z * programowania dynamicznego *? Powinieneś go znaleźć w każdej dobrej książce algorytmów. –
Czy wspólne podciągi są równe łańcuchom, ale różne, ponieważ sekwencje pozycji źródłowych są uważane za równe? Np. W twoim przykładzie istnieją 3 * 15 = 45 sposobów tworzenia wspólnego podciągu "AA", więc czy 'AA' powinno być wyprowadzane 45 razy, czy tylko raz? –
@j_random_hacker tylko raz. –