<代码随想录>陪伴刷题【P008 数组-开发商购买土地】

1.暴力求解的思路:

  其实就是枚举每一次竖切或横切的线,切完之后对两边的土地价值进行求和,算出两块土地的价值之差绝对值,每次对结果进行更新,选择最小的绝对值之差作为最终结果,很明显,???,时间复杂度为O(n^3)这里博主自己实现了一下代码:

#include <iostream>
#include <vector>
using namespace std;
#include <climits>//整数最大值最小值要引用
int main()
{
    int n,m;//二维数组的行数、列数
    cin>>n>>m;
    vector<vector<int>> arr(n,vector<int>(m,0));//定义二维数组
    int sum = 0;//记录数组中所有元素之和
    int result = INT_MAX;//作为最终结果输出,两块地之间的价值之差
    
    //初始化二维数组
    for(int i =0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>arr[i][j];
            sum += arr[i][j];
            
        }
    }
    
    //里面相关i,j,k的数字规律自己随便写几个例子推导一下即可
    for(int k=1;k<=n+m-2;k++)
    {
        int count = 0;//用来记录目前所有的数据和
        if(k<n)
        {
            for(int i=0;i<k;i++)
            {
                for(int j =0;j<m;j++)
                {
                   count+=arr[i][j];
                }
                result=min(result,abs(sum-count-count));
            }
        }
        else
        {
            for(int j=0;j<k-n+1;j++)
            {
                for(int i =0;i<n;i++)
                {
                   count+=arr[i][j];
                }
                result=min(result,abs(sum-count-count));
            }
            
        }
        
    }
    
    cout<<result<<endl;

    
    
    return 0;
}

2.前缀和思路:

  考虑到土地的划线只能竖着画或者横着画,因此可以新定义两个一维数组,分别存储每行和每列的数据总和,这样就可以避免每次枚举一个划线时要重新再遍历计算两块土地的总价值,将时间复杂度降了一阶,下面是代码解答:

#include <iostream>
#include <vector>
using namespace std;
#include <climits>//整数最大值最小值要引用
int main()
{
    int n,m;//二维数组的行数、列数
    cin>>n>>m;
    vector<vector<int>> arr(n,vector<int>(m,0));//定义二维数组
    int sum = 0;//记录数组中所有元素之和
    int result = INT_MAX;//作为最终结果输出,两块地之间的价值之差
    
    //初始化二维数组
    for(int i =0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>arr[i][j];
            sum += arr[i][j];
            
        }
    }
    
    //统计每行的数据和
    vector<int> arrrow(n,0);
    for(int i=0;i<n;i++)
    {
        for(int j =0;j<m;j++)
        {
            arrrow[i]+=arr[i][j];
        }
        
    }
    
    //统计每列的数据和
    vector<int> arrcol(m,0);
    for(int j=0;j<m;j++)
    {
        for(int i =0;i<n;i++)
        {
            arrcol[j]+=arr[i][j];
        }
        
    }
    
    
    int rowcut = 0;//记录横切的位置,用  前面所有元素之和  量化
    for(int i = 0;i<n;i++) 
    {
        rowcut +=arrrow[i];
        result = min(result,abs(sum-rowcut-rowcut));//减第一个rowcut得到另一块土地的价值,再减一个rowcut得到两块土地的价值差
        
    }
    
    int colcut = 0;//记录竖切的位置,用  前面所有元素之和  量化
    for(int j = 0;j<m;j++) 
    {
        colcut +=arrcol[j];
        result = min(result,abs(sum-colcut-colcut));//减第一个colcut得到另一块土地的价值,再减一个colcut得到两块土地的价值差
        
    }
    
    cout<<result<<endl;

    
    
    return 0;
}

  我们发现,顺着前缀和的思路,就是要把每行每列的和给计算并储存起来,后面还是按照顺序,切割线从上到下,从左到右的枚举,刚好和我们计算前缀和的顺序可以一致,那我们就可以将上述代码更简化一些,,就是在每计算完一行或一列的总和时,直接判断此时的划线处情况下的价值之差,简化后代码如下所示:

#include <iostream>
#include <vector>
using namespace std;
#include <climits>//整数最大值最小值要引用
int main()
{
    int n,m;//二维数组的行数、列数
    cin>>n>>m;
    vector<vector<int>> arr(n,vector<int>(m,0));//定义二维数组
    int sum = 0;//记录数组中所有元素之和
    int result = INT_MAX;//作为最终结果输出,两块地之间的价值之差
    
    //初始化二维数组
    for(int i =0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>arr[i][j];
            sum += arr[i][j];
            
        }
    }
    
    int count = 0;//用来记录目前所有的数据和
    
    //统计每行的数据和
 
    for(int i=0;i<n;i++)
    {
        for(int j =0;j<m;j++)
        {
           count+=arr[i][j];
        }
        result=min(result,abs(sum-count-count));
        
        
    }
    
    count = 0;
    //统计每列的数据和

    for(int j=0;j<m;j++)
    {
        for(int i =0;i<n;i++)
        {
            count+=arr[i][j];
        }
        
        result=min(result,abs(sum-count-count));
    }
    
    
    // int rowcut = 0;//记录横切的位置,用  前面所有元素之和  量化
    // for(int i = 0;i<n;i++) 
    // {
    //     rowcut +=arrrow[i];
    //     result = min(result,abs(sum-rowcut-rowcut));//减第一个rowcut得到另一块土地的价值,再减一个rowcut得到两块土地的价值差
        
    // }
    
    // int colcut = 0;//记录竖切的位置,用  前面所有元素之和  量化
    // for(int j = 0;j<m;j++) 
    // {
    //     colcut +=arrcol[j];
    //     result = min(result,abs(sum-colcut-colcut));//减第一个colcut得到另一块土地的价值,再减一个colcut得到两块土地的价值差
        
    // }
    
    cout<<result<<endl;

    
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值