一道简单dp

xwd丢给我的一道题,好像是他出的?

题面如下

(后面有中文解释)

A robot is located at the top-left corner of a m*n grid.
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid.
There is a positive integer in each small grid which means the score that the robot get when it passes this grid.
Now you need to calculate the top k total score when the robot reach the destination.
note: The top k total score may contain same total score got from different paths.
Example 1:
Input:
3 3
2
3 2 5
3 2 2
4 2 1
Output:
13 13
Example 2:
Input:
4 4
3
7 1 5 8
4 6 2 1
4 2 1 3
5 7 3 2
Output:
32 31 29
TEST 1: 1 <= n, m <= 4, k = 1
TEST 2-3: 1<= n, m, k<=4
TEST 4: 1<= n, m <= 100, k = 1
TEST 5-10: 1<=n, m, k<=100
For all, cost <= 100

题意:

简单说,有一个矩阵,矩阵的每个方格中放有若干金币,有一个机器人,他在矩阵的左上角,他要走到矩阵的右下角,他只能往下走或者往右走。要求他能得到的前k多的金币。输入规模如题面。

解:

本题简单版

应该有一道类似这样的dp,是求从左上角走到右下角,获得金币的最大值。这是比较好求的,因为对于所有i, j >= 2(下标从1开始)的第i行j列来说,它要么从上面i - 1行j列走过来,或者从左边i行 j - 1列走过来,对于每个点,选dp[i - 1][j]和dp[i][j - 1]中最大的,再加上本身的a[i][j]就是到达这个点时的最大值。还有边缘条件,对于第一行的每个点,除了第一行第一列以外,每个点因为只能从左边到达它,所以他们的dp值就是dp[1][i] = dp[1][i - 1] + a[1][i]。dp[1][1] = a[1][1]。每一列也如此。

进阶版

这道题让求的不是最大值,而是前k大值,那么可以考为每个点创建一个vector,也就是m*n个vector,设为vector v[m][n]。对应上面的逻辑就是,对于每个i, j >= 2,v[i][j]等于v[i - 1][j]和 v[i][j - 1]对应的vector中的前k个,也就是两个数组组合到一起,然后前k个就是v[i][j]。边缘的条件也类似上面的,对于第一行来说,每个vector都只有一个元素,就是从第一行第一列元素走到第一行第i列元素时的元素和。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
#define maxn 107
const int inf = 0x3f3f3f3f;
int n, m, k;
// 返回两个vector中的前k大元素组成的vector
vector findTopK(vector a, vector b, int t){
    vector temp;
    vector ans;
    for (int i = 0; i < (int)a.size(); i++){
        temp.push_back(a[i] + t);
    }
    for (int i = 0; i < (int)b.size(); i++){
        temp.push_back(b[i] + t);
    };
    sort(temp.begin(), temp.end());
    if ((int)temp.size() <= k){
        return temp;
    }
    else{
        for (int i = temp.size() - k; i < (int)temp.size(); i++){
            ans.push_back(temp[i]);
        }
        return ans;
    }
}
int main(int argc, char * argv[]) 
{
    while (cin >> n >> m >> k){
        int a[maxn][maxn];
        vector v[maxn][maxn];
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= m; j++){
                cin >> a[i][j];
            }
        }
         // 处理边缘条件
        int temp = a[1][1];
        v[1][1].push_back(a[1][1]);
        for (int i = 2; i <= n; i++){
            temp += a[i][1];
            v[i][1].push_back(temp);
        }
        temp = a[1][1];
        for (int i = 2; i <= m; i++){
            temp += a[1][i];
            v[1][i].push_back(temp);
        }
        //dp
        for (int i = 2; i <= n; i++){
            for (int j = 2; j <= m; j++){
                v[i][j] = findTopK(v[i - 1][j], v[i][j - 1], a[i][j]);
            }
        }
  
        for (int i = 0; i < k; i++){
            int t = (int)v[n][m].size() - i - 1;
            cout << v[n][m][t] << " ";
        }
        cout << endl;
    }
    return 0;
}

你可能感兴趣的:(一道简单dp)