我的杭电oj之旅——1003

    xiaoxiao2021-03-25  73

    问题描述:最大连续序列问题。第一行输入要解决的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(指向下一个位置的数字);

    转载请注明原文地址: https://ju.6miu.com/read-38418.html

    最新回复(0)