摘花生c++

题目

Hello Kitty想摘点花生送给她喜欢的米老鼠。

她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。

地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。

Hello Kitty只能向东或向南走,不能向西或向北走。

问Hello Kitty最多能够摘到多少颗花生。

输入格式

第一行是一个整数T,代表一共有多少组数据。

接下来是T组数据。

每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。

每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。

输出格式

对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。

数据范围

1≤T≤100,

1≤R,C≤100,

0≤M≤1000

输入样例:

2
2 2
1 1
3 4
2 3
2 3 4
1 6 5

输出样例:

8
16
思路1

本题涉及到最优解,考虑使用DP(动态规划)来做。对于动态规划的题,从状态表示和状态计算两方面考虑。

对于状态表示,又可以从集合定义和集合的属性两方面考虑。对于本题,我将集合f(i, j)定义为从某坐标(i, j)出发的所有路径,属性(即f(i, j)存的值)定义为摘到花生的最大数量。

而状态计算对应着集合的划分。对于本题,可以按第一步往哪个方向走来划分集合,分为两个小的集合:第一步向东走的,第一步向南走的。假设用二维数组a存每个坐标的花生数量。对于第一步向东走的集合,路径为:(1, 1) ->(1, 2) ->......,第一步都是在(1, 1)这个坐标,那摘到的花生数可以设为f(1, 1) = m(1, 1) + f(1, 2)。同理,对于第一步向南走的集合,路径为:(1, 1) ->(2, 1) ->......,第一步都是在(1, 1)这个坐标,那摘到的花生数可以设为f(1, 1) = m(1, 1) + f(2, 1)。然后两个小集合的最大值即可得到整个集合的最大值。

有人疑惑为什么这样可以摘到从西北角到东南角最大的花生数量。因为对于某个坐标,我们都会遍历东南两个方向,因此一定会到达东南角的。

代码1
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 110;
int t, r, c, m;

//a存各坐标花生数;total[i][j]存从(i, j)开始能获得的最大花生数量,为记忆化数组
int a[N][N], total[N][N];
int dx[] = {0, 1}, dy[] = {1, 0};

int dfs(int x, int y)
{
  int &v = total[x][y];

/*
对total[x][y]的各位取反,判断total[x][y]是否为-1,-1(1111 1111 1111 1111)取反后变为为0;
不为-1说明从(x, y)开始的路径已经遍历(记忆)过了,不需要重新遍历(记忆)
*/
  if (~v)
  return v;
  
  v = a[x][y];
  
  for (int i = 0; i < 2; i ++)
  {
    int nx = dx[i] + x, ny = dy[i] + y;
    //合理的坐标才能继续摘花生
    if (nx >= 1 && nx <= r && ny >= 1 && ny <= c)
    v = max(v, dfs(nx, ny) + a[x][y]);
  }

//遍历完两个方向后将结果v返回给上一层
  return v;
}

int main()
{
  cin >> t;
  while (t --)
  {
    /*
    因为某个坐标的花生数可能为0,因此要使用-1代表total[i][j]没有计算过从(i, j)开始能获得的最大花        生数量
    */
    memset(total, -1, sizeof total);
    cin >> r >> c;
    for (int i = 1; i <= r; i ++)
    for (int j = 1; j <= c; j ++)
    cin >> a[i][j];
    
    cout << dfs(1, 1) << endl;
  }
  
  return 0;
}
思路2

由于Hello Kitty只能向东或向南走,因此Hello Kitty到达某点坐标只能从西边或者北边来。那么我们可以将

  • 集合f(i, j)定义为:到达(i, j)的所有路径。
  • 属性:获得花生的最大数量。
  • 集合划分:从西边到达(i, j); 从北边到达(i, j)

f(i, j) = a[i][j] + f(i, j - 1);

f(i, j) = a[i][j] + f(i - 1, j);

代码2
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
//a存各坐标花生数;f[i][j]存到达(i, j)能获得的最大花生数量
int a[N][N], f[N][N];

int main()
{
  int t, r, c;
  cin >> t;
  
  while (t --)
  {
    //由于有多组不同的数据,因此每次都要重置为0
    memset(f, 0, sizeof f);
    cin >> r >> c;
    for (int i = 1; i <= r; i ++)
    for (int j = 1; j <= c; j ++)
    cin >> a[i][j];
    
    for (int i = 1; i <= r; i ++)
    {
      for (int j = 1; j <= c; j ++)
      {
        f[i][j] = max(f[i][j - 1], f[i - 1][j]) + a[i][j];
      }
    }
    
    cout << f[r][c] << endl;
  }
  return 0;
}
相关推荐
星星法术嗲人2 分钟前
【Java】—— 集合框架:Collections工具类的使用
java·开发语言
黑不溜秋的16 分钟前
C++ 语言特性29 - 协程介绍
开发语言·c++
一丝晨光21 分钟前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
天上掉下来个程小白23 分钟前
Stream流的中间方法
java·开发语言·windows
xujinwei_gingko34 分钟前
JAVA基础面试题汇总(持续更新)
java·开发语言
￴ㅤ￴￴ㅤ9527超级帅34 分钟前
LeetCode hot100---二叉树专题(C++语言)
c++·算法·leetcode
sp_wxf43 分钟前
Lambda表达式
开发语言·python
Fairy_sevenseven1 小时前
【二十八】【QT开发应用】模拟WPS Tab
开发语言·qt·wps
_GR1 小时前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
蜡笔小新星1 小时前
Python Kivy库学习路线
开发语言·网络·经验分享·python·学习