我的杭电oj之旅——1003

问题描述:最大连续序列问题。第一行输入要解决的case数,接下来每一行的第一个是序列的元素个数,后面跟着元素;输出最大和与序列号。


Sample Input
  
  
2 5 6 -1 5 4 -7 7 0 6 -1 1 -6 7 -5

Sample Output
  
  
Case 1: 14 1 4 Case 2: 7 1 6

本题有多种解法:

1、暴力破解。

2、分治策略。(我用的是分治策略,参考的是算法导论。结果对了,但是始终ac不过。)

#include<stdio.h>
#include<string.h>

typedef struct {
	int sum;
	int low,high;
}Max;

Max FindMaxSum(int num[],int low, int high);
Max FindCrossingMaxSum(int *num,int low,int high);

void main(){
	int **num;
	int T,i,j=0,c,sum=0,temp;
	Max m;
	
	scanf("%d",&T);
	num=(int **)malloc(sizeof(int)*T);

	for(i=0;i<T;i++){
		c=0;
		j=0;
		scanf("%d",&temp);
		num[i]=(int *)malloc(sizeof(int)*(temp+1));
		num[i][j++] = temp;
		while(c != '\n'){
			scanf("%d",&temp);
			num[i][j++] = temp;
			c = getchar();
		}

	}
	for(i=0;i<T;i++){
		m = FindMaxSum( num[i], 1, num[i][0]);
		printf("Case %d:\n%d %d %d\n", i+1, m.sum, m.low, m.high);
		if(i!=T-1)
			printf("\n");
	}
}

Max FindMaxSum(int *num,int low, int high){
	if(high == low){
		Max m;
		m.sum = num[low];
		m.low = m.high = low;
		return m;
	}
	else{
		int mid = (low + high) / 2;
		Max left, right, crossing;

		left = FindMaxSum(num, low, mid);
		right = FindMaxSum(num, mid+1, high);
		crossing = FindCrossingMaxSum(num, low, high);

		if(crossing.sum>=left.sum && crossing.sum>=right.sum)
			return crossing;
		else if(left.sum>=right.sum && left.sum >= crossing.sum)
				return left;
		     else
				return right;
	}
}

Max FindCrossingMaxSum(int *num,int low,int high){
	int i,sum=0,MaxLeftSum,MaxRighSum;
	Max crossing;
	for(i=(low + high)/2; i>=low; i--){
		sum += num[i];
		if(sum>=MaxLeftSum){
			MaxLeftSum = sum;
			crossing.low = i;
		}	
	}
	
	sum = 0;
	for(i=(low + high)/2+1; i<=high; i++){
		sum += num[i];
		if(sum>=MaxRighSum){
			MaxRighSum = sum;
			crossing.high = i;
		}
	}
	
	crossing.sum = MaxRighSum + MaxLeftSum;
	return crossing;
}




备忘:

(1)动态分配多维数组;

(2)二分算法的递归实现

(3)结构体的应用

3、动态规划。(最优解,仅转载算法思想,)

用数组a表示存储的数字序列,sum表示当前子段和,maxsum表示最大子段和。不妨设想:当sum为负数的时候: 
1.当下一个数字a[i]为正数的时候,sum+a[i] < a[i],不如将sum归零重新计算 
2.当下一个数字为负数的时候,sum+a[i]< 0 ,若再下一个数字还为负数,依旧可以得出和小于零……直到遇到一个正数,此时回到1的情况,不如将sum归零计算。 
综上所述,当sum为负数的时候,归零

那么再看sum为正数的时候: 
1.当下一个数字a[i]为正数的时候,当然选择加上a[i],并且可以更新maxsunm; 
2.当下一个数字a[i]为负数的时候,由于不知道后面数字的情况,无法做出决策。 
综上所述,当sum>maxsum的时候,要更新maxsum,并且一直累加a[i]

题目还要求输出这个子段的start位置和end位置。可以用x,y分别表示当前最优(大)的子段的开始和结束位置,然后再用sta和ed变量表示当前子段的开始和结束位置。结合上面的叙述: 
1.当sum>maxsum的时候,即需要更新的时候,就要更新x和y的位置; 
2.当sum< 0的时候,即需要使sum归零计算的时候,就需要把sta的位置置为i+1(指向下一个位置的数字);



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值