C++ 简单的动态规划练习

C++ 简单的动态规划练习,c++,algorithm,dynamic-programming,C++,Algorithm,Dynamic Programming,让我们有一个(给定尺寸的)小正方形的区域,每个正方形上都有一个值。从每个正方形,只能移动到正下方的正方形,或斜向左侧或右侧的正方形。任务是找到通过该字段的行程的最大组合值 例如输入 1 6 5 3 1 7 4 2 2 1 3 1 1 1 2 2 1 8 2 2 1 5 3 2 1 4 4 4 5 2 7 5 1 输出应该是32,但我的代码输出20 我的方法是通过以下方式,用尽所有可能的路线: y == last_row return value[x,y] f(x,y)

让我们有一个(给定尺寸的)小正方形的区域,每个正方形上都有一个值。从每个正方形,只能移动到正下方的正方形,或斜向左侧或右侧的正方形。任务是找到通过该字段的行程的最大组合值

例如输入

1
6 5
3 1 7 4 2
2 1 3 1 1
1 2 2 1 8
2 2 1 5 3
2 1 4 4 4
5 2 7 5 1
输出应该是32,但我的代码输出20

我的方法是通过以下方式,用尽所有可能的路线:

        y == last_row   return value[x,y]
f(x,y)  
        y != last_row   return value[x,y] + max(f(x-1,y+1),f(x,y+1),f(x+1,y+1))
我的方法、代码或两者都有错误吗

代码如下:

#include <iostream>
#include <vector>
#include <limits>

using namespace std;

typedef int T;

T max(T x, T y, T z) {
    if(x < y) {
        if(y < z) return z;
        else return y;
    }
    else {
        if(y > z) return x;
        else {
            if(x > z) return x;
            else return z;
        }
    }
}

//Finds the maximum amount of stones possibly gathered by following coordinates x,y
//The topmost left is (0,0), bottom right is (columns-1,rows-1)
T max_stones_found_following(T x, T y, vector< vector<T> > A) {
    //Reached the last row?
    if(y == A.size()-1) return A[x][y];
    else {
        T went_left, went_right, went_down;
        if(x-1 >= 0) went_left = max_stones_found_following(x-1, y+1, A);
        else went_left = numeric_limits<T>::min();
        if(x+1 <= A[x].size()-1) went_right = max_stones_found_following(x+1, y+1, A);
        else went_right = numeric_limits<T>::min();
        went_down = max_stones_found_following(x, y+1, A);
        return A[x][y] + max(went_left, went_right, went_down);
    }
}

int main() {
    //Initialization
    T test_cases, rows, columns, stones_found, max_stones;
    vector< vector<T> > A;
    cin >> test_cases;
    while(test_cases--) {
        //Field input
        cin >> rows >> columns;
        for(int i = 0; i < rows; i++) {
            vector<T> row;
            for(int j = 0; j < columns; j++) {
                T in;
                cin >> in;
                row.push_back(in);
            }
            A.push_back(row);
        }

        max_stones = 0;
        stones_found = 0;
        //Try starting at different positions in the first row
        for(int i = 0; i < columns; i++) {
            stones_found = max_stones_found_following(i, 0, A);
            if(stones_found > max_stones) max_stones = stones_found;
        }

        //Output
        cout << max_stones << endl;
    }
    return 0;
}
#包括
#包括
#包括
使用名称空间std;
typedef int T;
最大温度(Tx,Ty,Tz){
if(xz)返回x;
否则{
如果(x>z)返回x;
否则返回z;
}
}
}
//通过以下坐标x,y查找可能收集的最大石块数量
//最左上角为(0,0),右下角为(第1列,第1行)
T最大值(T x,T y,向量A){
//到最后一排了吗?
如果(y==A.size()-1)返回[x][y];
否则{
T向左,向右,向下;
如果(x-1>=0)向左移动=找到的石头最多(x-1,y+1,A);
else God_left=数值限制::min();
如果(x+1a;
cin>>测试案例;
而(测试用例--){
//字段输入
cin>>行>>列;
对于(int i=0;i>中;
行。向后推_(in);
}
A.向后推(世界其他地区);
}
最大石头数=0;
发现的石头=0;
//试着从第一行的不同位置开始
对于(int i=0;i最大石头)最大石头=发现的石头;
}
//输出
您的一些问题:

  • 方法
    max
    比需要的更复杂。您需要进行多次比较以找到最大值。请参见下文
  • 您的主要问题是使用
    i
    j
    反转,根据调用站点
    i
    表示
    第0行
    中的起始位置,以及在方法
    max\u found\u found\u
    中用作值矩阵的行
固定代码(顺便说一句,对于大输入数据,这是一个非常缓慢的解决方案,而不是动态编程):


如前所述,您可以计算到
行i
的最佳路径,只读取第一行
i
行,您可以动态执行(读取时,读取第一行,计算最佳起始位置,读取第二行,计算到第二行每一列的最佳路径,依此类推),如果输入非常非常大,这是非常好的。您也不需要保存最佳路径,直到
行1..i
,您只需要计算
最后一行
,并计算
实际行
的最佳路径。

动态编程是解决此问题的一种很好的方法。但就像匿名评论一样,y你没有使用它,或者至少没有以一种清晰的方式使用它

如果有
C
列,则有
C
可能的起始位置和
C
第二个位置,但有
3*C-2
对(第一、第二)。利用动态规划的方法是注意马尔可夫性,对于第二行中的每个单元格,在该单元格中结束的所有路径中,只保留得分最高的路径

然后,对于每个附加行,再次计算
3*C-2
路径,只保留其中的
C

重复,直到你到达底部

在实现方面,您应该有一个指向当前行的
C
最佳路径向量,并构建指向下一行的
C
最佳路径向量。然后下一行成为当前行(使用
vector::swap
)。每个“路径”必须至少存储累积值,但是存储访问过的位置的历史记录也可能很好

事实上,您甚至不需要将整个网格存储在内存中,您可以在读取每一行时对其执行所有处理

注意:这里使用动态规划使复杂性
R*C
而不是
C*3^R

提出一个真正的解决方案确实很有趣。警告:前面有指针

#include <iostream>
#include <sstream>
#include <vector>

void solve_one_case();

int main(int argc, char** argv)
{
    /* driver */
    const std::string input = "6 5\n"
                              "3 1 7 4 2\n"
                              "2 1 3 1 1\n"
                              "1 2 2 1 8\n"
                              "2 2 1 5 3\n"
                              "2 1 4 4 4\n"
                              "5 2 7 5 1";
    std::stringbuf inputstream(input, std::ios_base::in);
    auto const oldbuf = std::cin.rdbuf();
    std::cin.rdbuf(&inputstream);
    solve_one_case();
    std::cin.rdbuf(oldbuf);
    return 0;
}

void solve_one_case()
{
    /* get board size from input */
    int rows = 1, columns = 1;
    std::cin >> rows >> columns;
    std::vector<char> route(rows * columns, '|');

    /* get first row from input */
    std::vector<int> current_row, prev_row;
    current_row.resize(columns);
    for( int& start_score : current_row )
        std::cin >> start_score;

    /* get all cells from input, solving */
    char* pRoute = &route[columns];
    for( int row = 1; row < rows; ++row ) {
        prev_row = current_row;

        int cell = 0;;
        for( int column = 0; column < columns; ++column )
        {
            std::cin >> cell;
            if (column > 0 && prev_row[column-1] > current_row[column]) {
                current_row[column] = prev_row[column-1];
                *pRoute = '\\';
            }
            if (column + 1 < columns && prev_row[column+1] > current_row[column]) {
                current_row[column] = prev_row[column+1];
                *pRoute = '/';
            }
            current_row[column] += cell;
            ++pRoute;
        }
    }

    /* find best value in final row */
    int best_score = current_row[0], best_end = 0;
    for( int i = 1; i < columns; ++i ) {
        if (best_score < current_row[i]) {
            best_score = current_row[i];
            best_end = i;
        }
    }

    std::cout << "Best score is " << best_score << "\n";

    /* backtrack along route */
    int route_column = best_end;
    for( int row = 0; row < rows; ++row ) {
        char breadcrumb = '*';
        pRoute -= columns;
        std::swap(pRoute[route_column], breadcrumb);
        switch (breadcrumb) {
        case '/':  ++route_column; break;
        case '\\': --route_column; break;
        }
    }

    /* print routes */
    pRoute = &route[0];
    for( int row = 0; row < rows; ++row ) {
        std::cout.write(pRoute, columns);
        pRoute += columns;
        std::cout << '\n';
    }

    std::cout << std::flush;
}

看起来你的解决方案没有使用动态编程。这个练习的“动态”部分在哪里?我看到一个typedef
t
并且没有任何模板(除了向量向量的使用)。告诉你的讲师他们对“动态”的定义……不是。@WhozCraig:“动态编程”是系统工程中的一个主题,与动态键入或动态内存管理无关。我绝对不会使用
vector
以外的模板来解决这个问题。@BenVoigt当时不同的思想和认知流派都同意。除非得到指示,否则我也不会这样做(这里很可能是这样,但很难说)。如果我对路径标记使用
{124;}
,回溯部分可能会短得多,因为这些是连续的ASCII值。回答很好。但是,对于某些输入情况,您的代码会给出运行时错误。
#include <algorithm>
#include <iostream>
#include <vector>

typedef std::vector<int> row_t;
typedef std::vector<row_t> matrix_t;

int main() {
    // Initialization
    int test_cases, rows, columns;
    matrix_t A;
    std::cin >> test_cases;
    while (test_cases--) {
        std::cin >> rows >> columns;
        for (int i = 0; i < rows; i++) {
            row_t row(columns);
            int in;
            for (int j = 0; j < columns; j++) {
                std::cin >> in;
                row[j] = in;
            }
            A.push_back(row);
        }

        // Dynamic Programming Here

        // For storage the best path until each cell
        matrix_t best_A (rows, row_t(columns, 0));
        std::copy(A[0].cbegin(), A[0].cend(), best_A[0].begin());

        for (int i = 1; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                // right down
                if (j > 0 && best_A[i - 1][j - 1] + A[i][j] > best_A[i][j]) {
                    best_A[i][j] = best_A[i - 1][j - 1] + A[i][j];
                }
                // left down
                if (j < columns - 1 && best_A[i - 1][j + 1] + A[i][j] > best_A[i][j]) {
                    best_A[i][j] = best_A[i - 1][j + 1] + A[i][j];
                }
                // down
                if (best_A[i - 1][j] + A[i][j] > best_A[i][j]) {
                    best_A[i][j] = best_A[i - 1][j] + A[i][j];
                }
            }
        }

        // End Dynamic Programming

        auto it = std::max_element(best_A[best_A.size() - 1].cbegin(), best_A[best_A.size() - 1].cend());
        // Output
        std::cout << *it << std::endl;
    }
    return 0;
}
#include <iostream>
#include <sstream>
#include <vector>

void solve_one_case();

int main(int argc, char** argv)
{
    /* driver */
    const std::string input = "6 5\n"
                              "3 1 7 4 2\n"
                              "2 1 3 1 1\n"
                              "1 2 2 1 8\n"
                              "2 2 1 5 3\n"
                              "2 1 4 4 4\n"
                              "5 2 7 5 1";
    std::stringbuf inputstream(input, std::ios_base::in);
    auto const oldbuf = std::cin.rdbuf();
    std::cin.rdbuf(&inputstream);
    solve_one_case();
    std::cin.rdbuf(oldbuf);
    return 0;
}

void solve_one_case()
{
    /* get board size from input */
    int rows = 1, columns = 1;
    std::cin >> rows >> columns;
    std::vector<char> route(rows * columns, '|');

    /* get first row from input */
    std::vector<int> current_row, prev_row;
    current_row.resize(columns);
    for( int& start_score : current_row )
        std::cin >> start_score;

    /* get all cells from input, solving */
    char* pRoute = &route[columns];
    for( int row = 1; row < rows; ++row ) {
        prev_row = current_row;

        int cell = 0;;
        for( int column = 0; column < columns; ++column )
        {
            std::cin >> cell;
            if (column > 0 && prev_row[column-1] > current_row[column]) {
                current_row[column] = prev_row[column-1];
                *pRoute = '\\';
            }
            if (column + 1 < columns && prev_row[column+1] > current_row[column]) {
                current_row[column] = prev_row[column+1];
                *pRoute = '/';
            }
            current_row[column] += cell;
            ++pRoute;
        }
    }

    /* find best value in final row */
    int best_score = current_row[0], best_end = 0;
    for( int i = 1; i < columns; ++i ) {
        if (best_score < current_row[i]) {
            best_score = current_row[i];
            best_end = i;
        }
    }

    std::cout << "Best score is " << best_score << "\n";

    /* backtrack along route */
    int route_column = best_end;
    for( int row = 0; row < rows; ++row ) {
        char breadcrumb = '*';
        pRoute -= columns;
        std::swap(pRoute[route_column], breadcrumb);
        switch (breadcrumb) {
        case '/':  ++route_column; break;
        case '\\': --route_column; break;
        }
    }

    /* print routes */
    pRoute = &route[0];
    for( int row = 0; row < rows; ++row ) {
        std::cout.write(pRoute, columns);
        pRoute += columns;
        std::cout << '\n';
    }

    std::cout << std::flush;
}