SJTU OJ 1002 二哥种花生学习笔记

陌路散爱 提交于 2019-12-10 06:24:34
  1. 问题描述

                                                1002 二哥种花生

            http://acm.sjtu.edu.cn/OnlineJudge/problem/1002

    Description

    二哥在自己的后花园里种了一些花生,也快到了收获的时候了。这片花生地是一个长度为L、宽度为W的矩形,每个单位面积上花生产量都是独立的。他想知道,对于某个指定的区域大小,在这么大的矩形区域内,花生的产量最大会是多少。

    Input Format

    第1行有2个整数,长度L和宽度W。

    第2行至第L+1行,每行有W个整数,分别表示对应的单位面积上的花生产量A( \( 0 \leq A<10 \) )。

    第L+2行有2个整数,分别是指定的区域大小的长度a和宽度b。

    Output Format

    输出一个整数m,表示在指定大小的区域内,花生最大产量为m。

    Sample Input

    4 5
    1 2 3 4 5
    6 7 8 0 0
    0 9 2 2 3
    3 0 0 0 1
    3 3

    Sample Output

    38

    样例解释

    左上角:38 = (1+2+3) + (6+7+8) + (0+9+2)

    数据范围

    对于30%的数据: \( 1 \leq L,W \leq 100 \);

    对于100%的数据: \( 1 \leq L,W \leq 1000 \)。

    全部区域大小满足:\( 1 \leq a \leq L ,1 \leq b \leq W \) 。


  2. 我的第一次解决方案:

    1. 思路:

      1. 学习动态二维数组的创建

      2. 测试输入输出

      3. 算法实现

    2. int L(0), W(0); //由输入定义数组长度和宽度
      	cin >> L >> W;
              //百度到的方法,不知有没有更好的方法?
      	int **nut = new int*[L]; //分为两层定义
      	for (int i = 0; i < L; ++i) nut[i] = new int[W];
      	for (int i = 0; i < L; ++i){
      		for (int j = 0; j < W; ++j)
      			cin >> nut[i][j];
      	}
    3. 由sample 以为只要输出左上角的那一块的花生数量的和即可,提交后发现答案错误才明白应该是输出所有可能的地块中花生数量和最多的,所以应该要遍历整个数组。但是这样一来就有四重循环,十分不科学!

    4. //定义动态二维数组
      //@WuXueyang
      //1003
      
      #include<iostream>
      
      
      using namespace std;
      
      int main()
      {
      	int L(0), W(0);
      	cin >> L >> W; //输入花生地的长和宽
      	//定义数组
      	int **nut = new int*[L];
      	for (int i = 0; i < L; ++i)	nut[i] = new int[W];
      	for (int i = 0; i < L; ++i){
      		for (int j = 0; j < W; ++j)
      			cin >> nut[i][j];
      	}
      	int l, w,result(0),temp(0);
      	cin >> l >> w;//获得目标区块的大小
      	//遍历计算
      	for (int m =0; m < W-w+1; ++m){
      		for (int n = 0; n< L-l+1; ++n){
      			temp = 0;
      			for (int i = n; i < n+l; ++i){
      				for (int j = m; j < m+w; ++j){
      					temp += nut[i][j];
      				}
      			}
      			if (result <= temp)result = temp;
      		}
      	}
      	cout << result;//输出结果
      	//释放内存!
      	for (int i = 0; i < L; ++i)
      		delete[] nut[i];
      	delete[] nut;
      	return 0;
      }
  3. 学习改进               

    1. 就1002来说,它需要一个常用的技术——“前缀和”,尽管刚开始接触编程可能不太熟悉。思路大致是这么来的:你有没有发现在枚举的过程中反复计算了很多和?比如你在改变枚举的axb的矩形左上角时,其实每向右移动一格,矩形内只有最左边的一列被删除并仅新增了最右的一列。这就提示我们应该存在一种机制能够避免重复计算矩形内数的和。

    2. 具体做法是这样的:我们先考虑一维的情形,如果我事先计算出 pre[i] 表示前1-i个格子内数字之和,那么完成这个处理之后,每次想要得到任意一个区间 [l, r]的数字和,只需要计算 pre[r] - pre[l -1]即可。随即我们可以推广到二维,事先计算pre[i][j]表示以1, 1为左上角,i, j为右下角的矩形内数字之和。那么不难推出如果要取得以x1, y1为左上角 x2, y2为右下角的矩形内数字之和,只需计算 pre[x2][y2] - pre[x1 - 1][y2] - pre[x2][y1 - 1] + pre[x1 - 1][y1 - 1] 即可(画个图就清楚了)。

  4. 改进版

  5. //定义动态二维数组
    //@WuXueyang
    //1003
    
    #include<iostream>
    
    
    using namespace std;
    
    int main()
    {
    	int L(0), W(0), t(0);
    	cin >> L >> W; //输入花生地的长和宽
    	//定义数组
    	int **store = new int*[L];
    	for (int i = 0; i < L; ++i)	 store[i] = new int[W];
    	for (int i = 0; i < L; ++i){
    		for (int j = 0; j < W; ++j){
    			cin >> t;
    			if (j>0&&i>0)store[i][j] = store[i-1][j] + t + store[i][j-1] - store[i-1][j-1];
    			else if (j>0 && i == 0)store[i][j] = t + store[i][j-1];
    			else if (i > 0 && j == 0)store[i][j] = t + store[i - 1][j];
    			else store[i][j] = t;
    		}
    	}
    	int l, w, result(0), temp(0);
    	cin >> l >> w;//获得目标区块的大小
    	//遍历计算
    	for (int i = l - 1; i < L; ++i){
    		for (int j = w - 1; j < W; ++j){
    			if(i == l- 1 && j == w - 1)temp = store[i][j];
    			else if (i == l - 1 && j != w - 1)temp = store[i][j] - store[i][j - w];
    			else if (i != l - 1 && j == w - 1)temp = store[i][j] - store[i - l][j];
    			else temp = store[i][j] - store[i - l][j] - store[i][j-w] + store[i-l][j-w];
    			if (temp >= result)result = temp;
    		}
    	}
    	cout << result;//输出结果
    	//释放内存!
    	for (int i = 0; i < L; ++i)
    		delete[] store[i];
    	delete[] store;
    	return 0;
    }

时间: 1790ms 内存66056kb


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!