标签:
石柱上有一排石头键盘,每个键上有一个整数。请你在键盘上选择两个键,使这两个键及其之间的键上的数字和最大。如果这个最大的和不为正,则输出“Game Over"。
第1行:键的个数n。
第2..n+1行:键上的数字整数 ai。
−100≤ai≤100
对于70%的数据,2≤n≤1,000
对于100%的数据,2≤n≤1,000,000
一行,最大和或者”Game Over"。
5
3
-5
7
-2
8
13
3
-6
-9
-10
Game Over
这个题和之前关于求最大子列和的文章非常相似,但是又有不同,因为这是一个应用题...它要求至少要有两个键才行,所以最小的子序列也要保证长度大于等于2.
那么在这种情况下,我们原来的在线算法就不能直接使用了.
这里有两个新的在线算法来完成这个问题, 一个是专门为这个问题而改良的,一个是全新的思路可以解决原问题和这个新问题.
新在线算法1:
核心思想依然是:遇到了负数可以进行重置当前和. 但是在驱动的过程中要考虑到始终保持最小长度为2,所以要不断的错位来完成这件事情.
再处理的过程中,我们所需要决策的就是i一定是要续接上的,至于头部是继续上一次的,还是它的前一个位置 只需比较一下大小即可.
如果n[i-1]比当前的和大, 那么就从它开始续接不就好啦~ 如果当前和更大, 那就要继续下去
代码如下:
int main(){ int i,n,max,temp; cin>>n; int num[n]; for (i=0;i<n;++i) cin>>num[i]; max = temp = num[0]+num[1]; for (i=2;i<n;++i) { //对于每个i 都有两种结果 要么把它加进来 要么把当前片段重置为从i-1开始 temp = temp > num[i-1] ? temp + num[i] : num[i-1] + num[i]; //如果temp > num[i] 那么续接上num[i]肯定可以更大 //如果temp < num[i] 那么就可以从n[i-1]重置续接 那一定比以前大 if (max<temp) max = temp; } if (max>0) cout<<max; else cout<<"Game Over"; return 0; }
第二种方法是这样的思想:
1.一个连续子序列的和 =从第一个数到这个序列的尾端的和 - 从第一个数到这个序列尾端的和.
2.要想使等号左边最大,在每次计算中只要让 最后一项最小即可to
所以 我们要维护 smallest 然后所有的curtotal - smallest里找到最大值即可;
但是这里就涉及到一个非常关键的问题: 先维护最小值还是先更新当前连续子序列的和?
如果先维护最小值, 那么在
if (result < total - smallest)
result = total - smallest;
中的smallest就是指 前i-1个数组成的序列中连续子列和最小值
然后用total去减,最少得到的就是只有一个元素(如果smallest的尾部是i-1的话) 也就是经典问题
然而我们要求的是smallest必须指 前i-2个数组成的序列中子列和最小值, 这样减法之后至少有两个元素. 也就是应用题
要达成这个目的,我们需要用到一个技巧就是 后置更新法, 把smallest的更新 放在上面这句话的后边 那么它在被调用的时候,实际上还是到i-2的为止的最小值
代码如下:
int main() { int num(0); cin >> num; int result(0); int total(0), smallest(32785); //smalest 表示的是从第一个数开始 的 连续子序列和最小的时候的那个和 也就是以某一个数为尾端 //total 表示的是从 第一个数 开始 到 现在 为止的所有数的和 也就是以现在为尾端 //两者相减就是 从smallest结尾 到现在为止的子序列和 然后用result来维护最大值 for (int i = 0, temp; i < num; ++i) { cin >> temp; total += temp; //result = max(result, total-smallest) //在此处由于smallest维护的是到前2个数为止的 //那么相减的结果必然会至少包含前一个数 if (result < total - smallest) result = total - smallest; //smallest = min(smallest, total-temp ) //此处维护的smallest是从第一个数到当前数的前2个数的 //因为i饿total - temp 其实是到i-1为止的total if (smallest > total - temp) smallest = total - temp; } if (result > 0) cout << result << endl; else cout << "Game Over\n"; }
补充链接:
http://blog.csdn.net/hcbbt/article/details/10454947 六种方法解决连续子序列最大和
http://www.cnblogs.com/txd0u/p/3353355.html 1006题解
【算法学习笔记】33.在线算法 SJTU OJ 1006 求和游戏
标签:
原文地址:http://www.cnblogs.com/yuchenlin/p/4449186.html