NYOJ 44 & 104 - 最大连续子串和(矩阵最大子矩阵和)

1.NYOJ44-最大连续子串和

两种解法:
1.归并:(运行时间比DP长O(n*lgn),但是耗用内存小,好吧,其实dp不用开很大内存,O(1)的dp也可以解决,总体来说,dp更好一些)
无非三种情况,最大连续子串在mid左边,最大连续子串在mid右边,最大连续子串横跨左边和右边
递归调用即可

Code:
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"
#define N 1000005

using namespace std;

int t;
int n;
int data[N];
int sum;

int mergesort(int left,int mid,int right)
{
	int leftsum=0;
	int rightsum=0;
	int sum=0;
	for(int i=mid;i>=left;i--)
	{
		sum+=data[i];
		leftsum=max(leftsum,sum);
	} 
	sum=0;
	for(int i=mid+1;i<=right;i++)
	{
		sum+=data[i];
		rightsum=max(rightsum,sum);
	}
	return leftsum+rightsum;
}

int merge(int left,int right)
{
	int leftsum=0;
	int rightsum=0;
	int crosssum=0;
	int mid=(left+right)/2;
	if(left==right) return data[left];
 	leftsum=merge(left,mid);
 	rightsum=merge(mid+1,right);
 	crosssum=mergesort(left,mid,right);
 	if(leftsum>=rightsum&&leftsum>=crosssum) return leftsum;
 	else if(rightsum>=leftsum&&rightsum>=crosssum) return rightsum;
 	else return crosssum;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&data[i]);
		printf("%d\n",merge(1,n));
	}
	return 0;
} 

2.DP:
定义状态:
dp[i]表示以i结尾的最大连续子串的和

状态转移方程:
if dp[i-1] < 0   dp[i]=data[i]   //含义是,如果前面的最大连续子串和是负的,我们没必要让负值拉低我们的最大值,我们直接选取当前的元素即可
else  dp[i]=dp[i-1]+data[i]

Code:
 
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"
#define N 1000005

using namespace std;

int n;
int data[N];
int dp[N];

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int m=-99999999;
		dp[0]=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&data[i]);
		for(int i=1;i<=n;i++)
		{
			if(dp[i-1]>0) dp[i]=dp[i-1]+data[i];
			else dp[i]=data[i];
			m=max(m,dp[i]);
		}
		printf("%d\n",m);
	}
	return 0;
}        
这里我们可以优化一下,没必要开那么大的内存空间,我们直接记录前一个的数据就可以O(1)的空间复杂度

NYOJ 104 矩阵最大子矩阵和

Solution:
本题其实是上述问题的一个升级版本的变体
我们实际上可以将矩阵问题转化成以为问题
我们这样来转化,在这里我们开辟二维数组temp记录一直到每行下的每列的元素的和,那么我们只要用相应的temp减去上面的temp便可以枚举出二维矩阵的行的所有的情况,这时候,我们把行的数值当作上面NYOJ44问题的data域进行最大子列和的求解就可以了

Code:
 
#include"iostream"
#include"cstdio"
#include"cstring"
#define N 105

using namespace std;

int t;
int n,m;
int data[N][N];
int temp[N][N];
int dp[N];

int main()
{
	cin>>t;
	while(t--)
	{
		memset(temp,0,sizeof(temp));
		memset(dp,0,sizeof(dp));
		int maxp=-99999999; 
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				cin>>data[i][j];
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				temp[i][j]=temp[i-1][j]+data[i][j];
			}
		}
		for(int i=1;i<=n;i++)   //外层的两个循环遍历所有的行的情况 
		{
			for(int j=i;j<=n;j++)
			{
				for(int k=1;k<=m;k++)   //求最大连续子段和 
				{
					if(dp[k-1]>0) dp[k]=temp[j][k]-temp[i-1][k]+dp[k-1];
					else dp[k]=temp[j][k]-temp[i-1][k];
					maxp=max(maxp,dp[k]);
				}
			}
		}
		cout<<maxp<<endl;
	} 
	return 0;
}        



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值