由积分排名想到的一道算法题目《欢迎大家求解》
由积分排行想到的一道算法题目《欢迎大家求解》
比如****的积分形式(以下为假设),每当你获得一次积分,服务器便保留这时的时间以及总分。现在要求在哪一段时间内获得积分的效率最高(前提这段时间内最少获得100分)。求一个时间复杂度低于n^2的算法。除了穷举的算法O(n^2),有没有时间复杂度更低的算法呢?
以二维数组模拟以上问题(以下为一个例子)
时间 总分
0 0
10 5
30 28
44 71
99 97
110 105
125 120
198 181
203 190
230 201
时间和总分都是严格递增的。
效率计算方法举例:比如在时间段30到110之间的效率为(105-28)/(110-30)。
------解决方案--------------------
主要是要做得好有难度...办法肯定是有的...
------解决方案--------------------
我有两个问题:
1. 时间间隔不等长,能否让间隔等长?这样可以简化一下问题处理,且并没有失去你原有的意图。
2. “前提这段时间内最少获得100分”这句话不是很明白,是两个领进时刻之间所获得的分数必须超过100吗?如果是这样的话,楼主给出的那个示例数据中,是不是没有一个符合这个条件的?
请解释。
------解决方案--------------------
领进 = 临近
------解决方案--------------------
比如****的积分形式(以下为假设),每当你获得一次积分,服务器便保留这时的时间以及总分。现在要求在哪一段时间内获得积分的效率最高(前提这段时间内最少获得100分)。求一个时间复杂度低于n^2的算法。除了穷举的算法O(n^2),有没有时间复杂度更低的算法呢?
以二维数组模拟以上问题(以下为一个例子)
时间 总分
0 0
10 5
30 28
44 71
99 97
110 105
125 120
198 181
203 190
230 201
时间和总分都是严格递增的。
效率计算方法举例:比如在时间段30到110之间的效率为(105-28)/(110-30)。
------解决方案--------------------
主要是要做得好有难度...办法肯定是有的...
------解决方案--------------------
我有两个问题:
1. 时间间隔不等长,能否让间隔等长?这样可以简化一下问题处理,且并没有失去你原有的意图。
2. “前提这段时间内最少获得100分”这句话不是很明白,是两个领进时刻之间所获得的分数必须超过100吗?如果是这样的话,楼主给出的那个示例数据中,是不是没有一个符合这个条件的?
请解释。
------解决方案--------------------
领进 = 临近
------解决方案--------------------
- C/C++ code
#include <stdio.h> #include <math.h> #include <iostream> using namespace std; /* 0 0 10 5 30 28 44 71 99 97 110 105 125 120 198 181 203 190 230 201 */ double Time[]={0,10,30,44,99,110,125,198,203,230}; double score[]={0,5,28,71,97,105,120,181,190,201}; double Time1[20]={0}; double score1[20]={0}; double t=0,s=0; double begin =0,end=0; double MaxSum() { for(int i=1; i <10;i++) { Time1[i] = Time[i]-Time[i-1]; //把后一个减前一个的结果都保存下来 score1[i] = score[i] - score[i-1]; } //最大子段和 double res =0; for(int i=1;i<10;i++) { if((s+score1[i])/(t+Time1[i]) < score1[i]/Time1[i]) { t = Time1[i]; s = score1[i]; } else { t += Time1[i]; s += score1[i]; } if(s/t > res) res = s/t; } return res; } double fun() { //O(n*n)算法求得结果 double res =0; for(int i=1;i<10;i++) for(int j=0;j<i;j++) { double tmp =(score[i]-score[j])/(Time[i]-Time[j]); if(tmp > res) { res = tmp; begin = j; end = i; } } return res; } int main() { double res = MaxSum(); cout<<"time="<<t<<" score="<<s<<endl; cout<<res<<endl; res = fun(); cout<<"begin="<<begin<<" end="<<end<<endl; cout<<res<<endl; system("pause"); return 0; }
------解决方案--------------------
有n*log(n)的方法,如果给出的数据有序,还可以优化到O(n),方法就是斜率优化,维护一个凸包,只考虑凸包上的点,本身还是O(n)个状态,但使用单调队列可以让状态转移变成O(1)的,具体实现比较复杂,lz查查相关资料吧。
------解决方案--------------------
在时间-积分曲线上求导数,导数最大的地方积分最快
效率正比于得分次数n,或者正比于时间(看算法)
------解决方案--------------------
楼主,这是一维DP啊,我想起了以前ACM的时光。。。我只能想到NLOGN的……
------解决方案--------------------
用两个指针,一个在前一个在后,初始化这一段积分最少为100分,算出平均斜率。
1.后指针往后移,当且仅当后一段的斜率大于平均斜率,如果条件不满足,后指针停止前进。(跳到下一位)
2.前指针往后移,当且仅当后一段斜率大于平均斜率并且这一段积分最少为100分,不满足条件则停止。(跳到下一位)
3.重复1,2,如果后指针到最后一位,则停止前进。转为执行2.
4.两指针都不能动了,那么最高的效率段就出来了
------解决方案--------------------
注意,我所说的平均斜率是两个指针之间那一段的平均斜率
------解决方案--------------------
------解决方案--------------------
看了算法,我觉得我的智商可以忽略为零了。
------解决方案--------------------