编程练习-动态规划(最长公共子序列LCS)

来源:互联网 发布:燃烧冰flamingo数据 编辑:程序博客网 时间:2024/06/07 00:43

程序代码如下:

#include <stdio.h>#include <vector>#include <boost/scoped_ptr.hpp>template<typename T>class DualArrayInternal { public:  DualArrayInternal(T* array_data, size_t column_num) : array_data_(array_data), column_num_(column_num) {  }  T& operator[](size_t y) {    return array_data_[x_ * column_num_ + y];  }  const T& operator[](size_t y) const {    return array_data_[x_ * column_num_ + y];  }  void SetX(size_t x) {    x_ = x;  } private:  size_t x_;  T* array_data_;  size_t column_num_;};template<typename T>class DualArray { public:  DualArray(T* array_data, size_t column_num) : internal_(array_data, column_num) {}  DualArrayInternal<T>& operator[](size_t x) {    internal_.SetX(x);    return internal_;  }  const DualArrayInternal<T>& operator[](size_t x) const{    const_cast<DualArray*>(this)->internal_.SetX(x);    return internal_;  } private:  DualArrayInternal<T> internal_;};void Print(int value) {  printf("%c", value);}template<typename T, typename PrintFun>void PrintSequence(const std::vector<T>& array1,  const DualArray<char>& path_direction, const size_t i, const size_t j, PrintFun print_fun) {  if (i == 0 || j == 0) {    return;  }  if (path_direction[i][j] == 'S') {    PrintSequence(array1, path_direction, i - 1, j - 1, print_fun);    print_fun(array1[i - 1]);  } else if(path_direction[i][j] == 'U') {    PrintSequence(array1, path_direction, i - 1, j, print_fun);  } else {    PrintSequence(array1, path_direction, i, j - 1, print_fun);  }}template<typename T>void LongestCommonSubsequence(std::vector<T>& array1, const std::vector<T>&array2) {  boost::scoped_ptr<size_t> subsequence_length_buffer(new size_t[(array1.size() + 1) * (array2.size() + 1)]);  DualArray<size_t> subsequence_length(subsequence_length_buffer.get(), array2.size() + 1);  boost::scoped_ptr<T> path_direction_buffer(new char[(array1.size() + 1) * (array2.size() + 1)]);  DualArray<char> path_direction(path_direction_buffer.get(), array2.size() + 1 );  for (size_t i = 0; i <= array1.size(); ++i) {    subsequence_length[i][0] = 0;  }  for (size_t j = 0; j <= array2.size(); ++j) {    subsequence_length[0][j] = 0;  }  for (size_t i = 1; i <= array1.size(); ++i) {    for (size_t j = 1; j <= array2.size(); ++j) {      if (array1[i - 1] == array2[j - 1]) {          subsequence_length[i][j] = subsequence_length[i - 1][j - 1] + 1;          path_direction[i][j] = 'S';        } else if (subsequence_length[i - 1][j] >= subsequence_length[i][j - 1]) {          subsequence_length[i][j] = subsequence_length[i - 1][j];          path_direction[i][j] = 'U';        } else {          subsequence_length[i][j] = subsequence_length[i][j - 1];          path_direction[i][j] = 'L';        }              }  }  for (int i = 0; i <= array1.size(); ++i) {    for(int j = 0; j <= array2.size(); ++j) {      printf("%zd ", subsequence_length[i][j]);    }    printf("\n");  }       PrintSequence(array1, path_direction, array1.size(), array2.size(),Print);  printf("\n");}class Test{};int main(int argc, char** argv) {  char array1[] = {'B', 'D', 'C', 'A', 'B', 'A'};  std::vector<char> array_vector1(array1, array1 + sizeof(array1) / sizeof(char));  char array2[] = {'A', 'B', 'C', 'B', 'D', 'A', 'B'};  std::vector<char> array_vector2(array2, array2 + sizeof(array2) / sizeof(char));  LongestCommonSubsequence<char>(array_vector2, array_vector1);}

关键是下标的处理问题,容易出现错误的几点是:

1)保存矩阵的行列数量要计算清楚,矩阵多出1行和1列用于存储初始值,这样初始时i-1和j-1的位置不会溢出

2)由于矩阵的下标从1开始,而传入的向量下标从0开始,因此访问向量时下标要-1,对于Print函数也是如此

3)注意DualArray的常量成员函数实现,为了满足常量参数调用的需要,内部需要转型操作

4)Print的实现允许用户定义的访问函数,通过函数模板参数实现