网易云课堂-陈越、何钦铭-数据结构-2016春,学习笔记,1.3 应用实例:最大子列和问题


01-复杂度2 Maximum Subsequence Sum   (25分)

Given a sequence of KKK integers { N1N_1N1,N2N_2N2, ..., NKN_KNK }. A continuous subsequence is defined to be { NiN_iNi,Ni+1N_{i+1}Ni+1, ..., NjN_jNj } where 1≤i≤j≤K1 \le i \le j \le K1ijK. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integerKKK (≤10000\le 1000010000). The second line contains KKK numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices iii and jjj (as shown by the sample case). If all the KKK numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:

10 1 4

因为以前做过类似的题,所以第一时间就想到了类似在线算法的想法,可是有几个问题没想清楚。

-------------------------------------------------------------------------------------------------------------------------------

自己的想法:


关键是依据连续的一段对整体的“贡献”的正负,判断什么时候保留,什么时候去掉。

相当于两个指针(前、后),什么时候向后移动的问题。

两个“考察”指针——考察1和考察2在前面和后面移动。


-------------------------------------------------------------------------------------------------------------------------------

看完老师的解答发觉最近智商严重掉线。。。

其实这个有点本末倒置了。

所谓的头和尾只是需要保存的两个位置罢了。


头和尾都是跟着最大值动的。


而且我有一个问题没想明白,就是如果后面的应该“卡断”怎么办,比如Maxsum,-6,1。或者应该放弃前面的一块直接跳转到后面的一块应该怎么处理。

这个问题可以分为两部分:

获得最大值。

(在确定MaxSum=ThisSum之后)保存位置。

关于获得最大值。

一定是通过某种意义上的遍历,比较ThisSum和MaxSum之间的关系。

经过http://www.cnblogs.com/CCBB/archive/2009/04/25/1443455.html的启发:

在线算法其实就是遍历算法的一个改进。


先写一个简单的遍历算法。


//

#include <iostream>
//#include <windows.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int traversal(int a[], int K, int & head, int & tail)
/*a[]是数组,K是数组元素个数,头和尾用引用的形式保存数据(Is it necessary?)*/
{
	int Maxsum = a[0];//!!!注意!!!,这个只是不能随便初始化为0,
                         //否则全是负数的序列的maxsum难道为0? 
	int ThisSum = 0;
	head = 0;
	tail = 0;
	for (int i = 0; i < K; i++)//i是头
	{
		ThisSum = 0;
		for (int j = i; j < K; j++)//j是尾
		{
			ThisSum = ThisSum + a[j];
			if (ThisSum>Maxsum)
			{
				Maxsum = ThisSum;
				head = i;
				tail = j;

			}

		}

	}
	if(Maxsum<0)
	{
		Maxsum=0;
		head=0;
		tail=K-1;//不是K,是K-1.。。这智商也是醉了。。。 
		
	}
	

	return Maxsum;
}


int main()
{
	int MaxSum = 0;
	int head = 0, tail = 0;
	int K = 0;
	int a[10000] = {0};
	scanf("%d", &K);
	//scanf_s("%d",K,1);
	for (int i = 0; i < K; i++)
	{
		scanf("%d",&a[i]);
		//scanf_s("%d",a[i],10000);
	}
	MaxSum = traversal(a,K,head,tail);
	printf("%d %d %d",MaxSum,a[head],a[tail]);
	return 0;
}

遇到了一个问题,题目要求输出“the first and the last numbers”,我傻乎乎地输出的是index。。。结果咋改都通不过,最后还是看了一位小哥的代码才恍然大悟。。。果然智商掉线。。。

//



尾巴不用担心,本质上就是遍历么,如果后面的数字不符合要求不更新maxsum和head,tail就可以了。


-------------------------------------------------------------------------------------------------------------------------------

好了,由上面的图片可以看到,这个复杂度为N*N的算法还是有改进的空间的,就是“是否保留前面的部分”的问题。

也就是说,“Thissum”的计算是可以优化的。正如http://www.cnblogs.com/CCBB/archive/2009/04/25/1443455.html中所述,

我们要优化的是Thissum的前一个指针i

遍历是为了取到全局的maxsum,而如果前面的某一段小于0,那么它对后面的序列的贡献就是负的了,应该抛弃。

i就是这样“优化”的——i不用遍历了,直接通过“取舍”得到一个合适的值(对某一段序列来说,为了使他的值最大,i应该为多少)





#include <iostream>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//先写函数 
int online1 (int a [], int k, int & head, int & tail)
{
	int Maxsum=a[0];
	int Thissum=0;
	int IndexTail=0;//粉色 
	int IndexHead=0;//绿色 
	for (IndexTail=0;IndexTail<k;IndexTail++)
	{
		Thissum=Thissum+a[IndexTail];//计算thissum(紫色)
		//Maxsun?
		if(Thissum>Maxsum)
		{
			Maxsum=Thissum;
			head=IndexHead;
			tail=IndexTail;
		} 
		//是否保留?
		//这里<0而不是<=0,就是因为题目的要求“smallest” 
		if(Thissum<0)
		{
			Thissum=0;
			//IndexTail=IndexTail+1;
			IndexHead=IndexTail+1;
		}
		
	}
	if(Maxsum<0)
	{
		Maxsum=0;
		head=0;
		tail=k-1;
	}
	return Maxsum;
} 

int main() {
	int MaxSum=0;
	int head,tail=0;
	int K=0;
	int a[10000]={0};
	scanf("%d",&K);
	for(int i=0;i<K;i++)
	{
		scanf("%d",&a[i]);
	} 
	MaxSum=online1(a,K,head,tail);
	printf("%d %d %d",MaxSum,a[head],a[tail]);
	return 0;
}


出现了一个逻辑问题,主要是尾部的指针是不是应该+1的问题,通过dev C++的调试已经解决。





编译通过


-------------------------------------------------------------------------------------------------------------------------------

最后还要编写一个“分而治之”算法的程序。

-------------------------------------------------------------------------------------------------------------------------------

这个问题是要找到“所有子列和的最大值”。

“所有”可以分成“部分”之和。


-------------------------------------------------------------------------------------------------------------------------------

由此我们可以知道:

1)智商掉线的时候应该刷刷算法题补补智商。。。

2)遇到问题不要急于想出一个聪明的算法,可以先想一个笨笨的算法,逐步优化。


-------------------------------------------------------------------------------------------------------------------------------

遇到的一些问题:

C++开发模式,比如什么应该写在头文件里?什么写在cpp里?一个cpp写一个函数?cpp的命名规则?dll是什么?

平时没觉得怎么样,最近一动手做点实际的项目就感觉智商掉线,水平捉急。。。

-------------------------------------------------------------------------------------------------------------------------------

下面是课程中遇到的一些零散的知识点:


const int a[5]与int a[5]在含义与语法的区别

const是常量修饰关键字,被它修饰的变量在定义时赋值,之后不能对这个变量赋值,如果强制进行赋值会产生出错处理,例如,const int a[5]={1,2,3,4,5};a[0]=3;

/*出错,对数组a[]中任意一个再次赋值都会出错*/ ,

而int a[5]中除了定义时赋值,再次对数组a[]中任何一个元素都可以赋值。


int max(const inta[]) 与int max(int a[])的区别


这里const修饰数组,表示传入函数内的a的元素不可被修改——若进行修改(例如对其赋值),则会产生无法修改const对象的编译错误;而没有被const修饰的函数参数进行修改不会引起这个编译错误。由于数组传递参数时会退化为指针,也可以作为指向const对象的指针理解。

以下分别是等价的函数头:

int max(const int a[])和int max(const int* a);

int max(int a[])和int max(int* a)。

注意:

按值传递复制了参数,形式参数a和调用函数的实际参数是不同对象,在函数内修改形参不会影响实参的值,像int foo(int a)和int foo(const int a)对调用者而言是完全等价的(对函数内部而言,前者a可修改,后者不可修改),因此const可以省略;

但是数组的元素和指针指向对象的const特性并不受按值传递的影响,因此若修饰指针或数组参数不加const,当修改参数指向的对象,影响函数外部的值时编译器不会产生编译错误,往往会导致不期望的后果;所以如果不需修改数组的元素或指针指向的值,尽量在前面加上const




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值