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<int> 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 <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#include <windows.h>
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<int> findTopK(vector<int> a, vector<int> b, int t){
vector<int> temp;
vector<int> 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<int> 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;
}