摘花生c++

题目

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

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

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

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

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

1.gif

输入格式

第一行是一个整数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
#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
#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;
}

相关推荐

  1. AcWing 1015. 花生

    2024-03-10 21:50:03       44 阅读
  2. 12.15每日一题(备战蓝桥杯花生

    2024-03-10 21:50:03       52 阅读
  3. C 嵌入式系统设计模式 04

    2024-03-10 21:50:03       54 阅读
  4. 猴子香蕉python

    2024-03-10 21:50:03       59 阅读
  5. 【Leetcode】741.樱桃

    2024-03-10 21:50:03       36 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-10 21:50:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-10 21:50:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-10 21:50:03       82 阅读
  4. Python语言-面向对象

    2024-03-10 21:50:03       91 阅读

热门阅读

  1. 基于动态内存设计的通讯录

    2024-03-10 21:50:03       38 阅读
  2. 分布式全局唯一ID,我这就告诉你怎么搞!

    2024-03-10 21:50:03       48 阅读
  3. NOIP 2018 普及组初赛试题及解析

    2024-03-10 21:50:03       46 阅读
  4. openCV源码安装与卸载

    2024-03-10 21:50:03       41 阅读
  5. leetcode 第388场周赛第一题

    2024-03-10 21:50:03       33 阅读
  6. Gitlab部署流程

    2024-03-10 21:50:03       42 阅读
  7. 分布式锁从0到1落地实现01(mysql/redis/zk)

    2024-03-10 21:50:03       44 阅读
  8. SpringBoot集成MySQL

    2024-03-10 21:50:03       46 阅读