poj1050

11 篇文章 0 订阅

题目有难度,主要是转化思想,将二维转化为一维,就将题目转化为一维的连续最大整数和问题了。大致题意为:

给定一个n*n的正方形,要在其中找一个子矩形,要求该矩形的所有组成元素之和最大。

分析如下:由于是找子矩形,且其元素之和最大,若将矩形的一边看作一个元素,那么矩形就成为了线段,那么问题就转化为一维的求连续最大整数和问题了。这里,矩形的一边取正方形的第一行,记为x,另一边取矩形的列记作y。那么x可由1个元素组成,可以取第1行第1个元素,或第2、3、4、……、n个元素,也可由2、3、4……n个元素组成,一共有(1+n)*n/2种不同选择策略。对每一种选择,将x边元素看作一个元素(相加求和成为一个元素),求解该矩形“线段“情况下的最大整数和dp,然后与记最大子矩阵的max_dp比较取大值,则枚举完所有可能的矩形”线段“dp后,即可求出最大子矩阵和。复杂度为O(n^3)

而一维连续最大整数和问题的dp如下:

令dp[i]表示以第i个元素结尾,从1——i元素中最大连续整数和(注意必须包含第i个元素)。

状态转移方程如下: dp[i]=max{dp[i-1]+record[i],record[i]}

这题充分说明了复杂问题可以转化为简单问题,关键是对简单问题的特征要明了,另外就是对于问题的特征理解透,善于灵活转化变形,这样才能有所突破。

下面是代码: 184K+32MS

#include <stdio.h>
#include <stdlib.h>
#define Max 110
#define Maxx(a,b) (a)>(b)?(a):(b)
#define Inf 100000010 // 定义正无穷
int dp[Max]; // 求解每一个矩形”线段“的最大连续整数和
int record[Max][Max]; //记录正方形
int n;
int max_dp; // 保存结果
int main(){
	scanf("%d",&n);
	int i,j,k;
	max_dp=-Inf;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++){
			scanf("%d",&record[i][j]);
			if(record[i][j]>max_dp)
				max_dp=record[i][j];
		}
	if(max_dp<=0) //若小于等于0,则可推出子矩形元素之和最大值为max_dp
		printf("%d\n",max_dp);
	else{ //否则需要枚举每个”矩形线段“
	max_dp=-Inf; // 初始化为负无穷
	int begin,end;
	for(i=1;i<=n;i++){ // x边的元素个数
		for(j=1;j<=n-i+1;j++){ // x边的开始元素位置
			begin=i,end=j+i-1; 
			dp[0]=0;
			for(k=1;k<=n;k++){ //y边枚举dp,求解最大值
				int temp=0;
				for(int s=begin;s<=end;s++) //将x边元素求和,转化为一个元素,成为一维情形
					temp+=record[k][s];
				dp[k]=Maxx(dp[k-1]+temp,temp);  
				max_dp=Maxx(dp[k],max_dp); //求最大值
			}
		}
	}
	printf("%d\n",max_dp); //输出最大值
	}
	return 0;
}
					


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值