虽然下周就考试了,还有很多没复习……我还如此淡定地花了整整一个下午+晚上想了一个实际问题……(其实也不是那么特别实际,但的确是来自于现实生活的DP问题)

问题+讨论的URL:http://topic.csdn.net/u/20110421/17/dc8e63bf-7992-487f-a112-049cf390cb1c.html?seed=1122826158&r=72946293#r_72946293

(因为考虑到很多人很懒,不想打开URL去看,我把里面重点的内容复制过来)

问题陈述:

比如CSDN的积分形式(以下为假设),每当你获得一次积分,服务器便保留这时的时间以及总分。
现在要求在哪一段时间内获得积分的效率最高(前提这段时间内最少获得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)。

于是在仔细思考了这种计算方法之后,我提出了这个质疑:

积分是以时间点为单位获得的。
比如,如果input为:
0 0
5 10
10 20
20 100

实际上的获得积分的情况为:
0 0
5 10
10 10
20 80 (在这一点获得了80分)

定义 slope = 在单位时间内获得的最大积分,那么明显在 5~20区间内,slope最大,为:100/(20-5) = 6.67。

但题目给的理解方式为,积分差 = A时间点得分 - B时间点得分;所以依照这个方法计算,slope = 100/(20-0)= 5;
这实际上是从一个得了分的时间点之后开始算的,但没有算这个时间点的得分(就是说,多算了A时间点之后到A之后第一次得
分之前的时间)。
明显这样的计算方式并不能算出最大的slope。

但既然现在已经在考虑问题本身,那么我们来看看依照原来的计算方法,怎样算。重新表述一下这个问题:

input:
若干行 以 time,score 形式的数据,其中time表示一个时间点,score表示在这个时间点的累积得分;time、score均严格递增。

output:
end,start;
其中end,start的意义为:
定义 Δslope = (time[i] - time[j])/(score[i]-score[j]);
end,start满足:
1. score[end] - score[start] >= score interval  (这里题目给的是100)
2. Δslope = (time[end]-time[start])/(score[end]-score[start]) 的值为最大。

于是开始漫长的思考过程...发现 (x-时间,y-得分) 的坐标系不是很便于思考(需要考虑在Δy>score interval),所以把坐标系变成了(x-得分,y-时间)——这样只需要保证在x轴上大于score interval就好了;但slope从原来寻找最大slope,变成了现在寻找最小slope。

思维过程很漫长……建议下周期末考试,要抓紧复习,直接给出我回复的、成型了的想法:

这个方法的time complexity: O(n) ~~~

为了思考方便,首先我做了一个坐标系的转化:
把time看成纵坐标(y轴),score看成横坐标(x轴);这样问题转化为,求在Δscore (即Δx
)>= 100 (为了一般性,我在代码里面用scoreInterval表示这个数字)的时候,使得slope最
小的 startIndex 和 endIndex。
假设一共输入了n组数据。(代码中的 score.size()等价于n)

*****************************preprocess***************************************
建立两个表:predecessor[n], minSlopeStartIndexTable[n];
第一个表,predecessor[i]表示:
对于index i,startIndex = predecessor[i]是i之前的第一个使得 Δscore = score
[i] - score[startIndex] >= scoreInterval 的 startIndex。对应的建表方法见code。这步
需要 O(n)的时间。

第二个表,minSlopeStartIndexTable[n]表示:
对于index i,假设 sIndex = minSlopeStartIndexTable[i],那么 对于j = 从index
0开始,到index i,使得 所有终结于i的点中,slope(j,i)的值为最小的,记为sIndex,存储
在这个表中。
易知递归关系有:
minSlopeStartIndexTable[i] =
(slope(minSlopeStartIndexTable[i-1],i)<slope(i-1,i))?
minSlopeStartIndexTable[i-1]:i-1;
这一步需要O(n)的时间。

*****************************calculation***************************************
于是我们开始进行计算:
保持一个minSlope:这是进行到当前计算状态中,能得到的最小的slope。初始化为正无穷
(INF,一个非常大的数值)
同时有bestStartIndex,bestEndIndex表示对应minSlope的两个index。

对于index i:
假设:minSlope是从0~i-1中所有可能中的最小斜率。
首先我们需要计算从predecessor[i]到i的斜率,同minSlope比较;
然后考虑predecessor[i]之前的最小的斜率(即从 minSlopeStartIndexTable
[predecessor[i]] 到 predecessor[i]的斜率),如果比(predecessor[i] 到i 的斜率)要小
,那么他们合起来的斜率是一个比predecessor[i]到i的斜率更小的斜率。所以,我们用这个和
minSlope比较。
在以上比较进行完成之后,可以保证 minSlope 是从 0~i中所有可能中的最小斜率。
每次对 index i的比较需要 O(1)的时间,一共进行n次,所以也是O(n)的时间。

*****************************Test Case***************************************
另外,为了测试方便,给出Test Case:
(测试的人把code里面的freopen、结尾的while(1)取消注释就好了;同时建立测试文件
MaxSlopeOverInterval_in.txt,保存在和这个code的相同目录下)

然后,这是做出来的code,个人感觉注释写得还是很清楚的:

#include <iostream>
#include <vector>

#define INF 1000000000
using namespace std;

vector<int> timePoint, score;
int scoreInterval = 100; // by default the score interval is 100

double slope(int startIndex,int endIndex){
return ((double)(timePoint[endIndex] - timePoint[startIndex]))/(
score[endIndex] - score[startIndex]);
}

int main(){
// freopen("MaxSlopeOverInterval_in.txt","r",stdin);

// handle the input
int t,p;
while(scanf("%d%d",&t,&p)!=EOF){
timePoint.push_back(t);score.push_back(p);
}

for(int i=0;i<score.size();i++){
printf("%d: %d, %d\n",i,timePoint[i],score[i]);
}

// preporcessing:
// *1. store the predecessor of score[i]
int predecessor[score.size()]; int predecessorIndex = 0;
for(int i=0;i<score.size();i++){
if(score[i]<scoreInterval) predecessor[i] = -1;
else{
while(score[i] - score[predecessorIndex + 1] >= scoreInterval){
predecessorIndex++;
}
predecessor[i] = predecessorIndex;
}
printf("predecessor index of %d: %d\n",i,predecessorIndex);
}
// *2. stores the minSlopeStartIndex from its value to i.
// minSlopeStartIndexTable[i] is the startIndex of the slope, and
// i is the endIndex of the slope, which makes the slope(j,i) to be
// smallest for all j from 0 to i-1
int minSlopeStartIndexTable[score.size()];
minSlopeStartIndexTable[0]=0;minSlopeStartIndexTable[1]=0;
for(int i=2;i<score.size();i++){
minSlopeStartIndexTable[i] =
(slope(minSlopeStartIndexTable[i-1],i)<slope(i-1,i))?
minSlopeStartIndexTable[i-1]:i-1;
printf("%dth minSlope: %d\n",i,minSlopeStartIndexTable[i]);
}

int formerBestStartIndex=0;
// score[i] - score[formerBestStartIndex] is the min for start = 0~i,
// which satisfies score[end] - score[start] > scoreInterval
int bestStartIndex=0,bestEndIndex=0;
// the start and end of the time period with max score/timePeriod gained
double minSlope = INF;

/* basic idea:
to compare (minSlope) and
slope(iScorePredecessorIndex,i), slope(formerBestStartIndex,i)
*/
for(int i=1;i<score.size();i++){
int iScorePredecessorIndex = predecessor[i];
if(iScorePredecessorIndex >= 0){
// compare (minSlope) and slope(islope(iScorePredecessorIndex,i))
printf("slope from %d to %d: %lf\n",iScorePredecessorIndex,i,
slope(iScorePredecessorIndex,i));
if(minSlope > slope(iScorePredecessorIndex,i)){
minSlope = slope(iScorePredecessorIndex,i);
bestStartIndex = iScorePredecessorIndex;
bestEndIndex = i;
}

// compare (minSlope) and slope(formerBestStartIndex,i)
formerBestStartIndex = minSlopeStartIndexTable[predecessor[i]];
printf("%dth element's former Best Start Index: %d, slope = %lf\n",
i,formerBestStartIndex,slope(iScorePredecessorIndex,i));
if(minSlope > slope(formerBestStartIndex,i)){
minSlope = slope(formerBestStartIndex,i);
bestStartIndex = formerBestStartIndex;
bestEndIndex = i;
}
}
}

printf("\n\nThe best one is : start time = %d, end time = %d, slope = %lf\n",
timePoint[bestStartIndex],timePoint[bestEndIndex],1/minSlope);

// while(1);
return 0;
}

转载于:https://www.cnblogs.com/flyfy1/archive/2011/04/23/2025924.html

讨论记录:求大于一个时间段的最大平均积分,O(n)时间实现相关推荐

  1. php几个时间段去除重复,一个时间段内各地区数据和,发现重复地区不相加

    有2个表 第一个表是f_city(字段:city_id和字段city_name) 第二个表是f_chengjiao(字段:id.city_id.area.taoshu.fang_time) 关联字段是 ...

  2. 《测试驱动开发应用实践》讨论记录

    <测试驱动开发应用实践>讨论记录 Design & Pattern团队第二次交流会 主题:测试驱动开发应用实践 日期:本周星期五(2005年1月7日)晚20:00--21:00 地 ...

  3. python excel 分组统计一个时间段内的数据,如三个月内,但不限于某个时间起止,是任何三个月的长度内

    """ 分组统计一个时间段内的数据,如三个月内,但不限于某个时间起止,是任何三个月的长度内 """import pandas as pd i ...

  4. js 日期比较大小,js判断日期是否在区间内,js判断时间段是否在另外一个时间段内...

    /** * 日期解析,字符串转日期 * @param dateString 可以为2017-02-16,2017/02/16,2017.02.16 * @returns {Date} 返回对应的日期对 ...

  5. Kafka拉取某一个时间段內的消息

    一般来说我们都使用Kafka来记录用户的操作记录以便后续分析. 但是通常使用的时候需要按天来统计每天的去重用户数.点击量之类的. 这个时候如果直接拉某个topic的数据的话,就需要判断每个消息的时间戳 ...

  6. 判断一个时间段是否经过了另一个时间段

    场景: IOT设备存在离线与恢复时间记录,每一次离线和恢复记为一个周期即一条数据, 现在需要统计出在某个时段存在离线记录的数据,如果目前未恢复,没有恢复时间,恢复时间置为9999-01-01 00:0 ...

  7. C语言计算数字乘积根,c语言,求任意一个整数各位数字之积

    点击查看c语言,求任意一个整数各位数字之积具体信息 答:求整数各位和,将整数各个位分离出来的方法(除10取模)很常用. 函数如下 int intsum(int n) { int sum = 0; wh ...

  8. 2020-3.31-26-超能陆战队-第一次需求讨论记录

    2020-3.31-26-超能陆战队-第一次需求讨论记录 会议截图 会议讨论纪要 1.段:解决的主要痛点:匿名提出,匿名回复.实现全部匿名,这样就不用担心会被人认出来或者影响自己的正常生活.可以发表一 ...

  9. 精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结

    精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结 精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结2008-01-28       15:30最近由于某些原因,不能 ...

最新文章

  1. MySQL数据copy
  2. 使用apidocJs快速生成在线文档
  3. Android ProGuard使用要点!
  4. 网络安全技术 —— 防火墙技术基础
  5. web.xml中load-on-startup的作用
  6. ie 7 beta 2出来了
  7. 学习knex过程中好的参考资料整理
  8. vue项目首屏加载过久处理笔记
  9. Eclipse 中 去掉控制台最大行数限制
  10. 【微软2014实习生及秋令营技术类职位在线測试】题目1 : String reorder
  11. Codeforces Manthan, Codefest 18 (rated, Div. 1 + Div. 2) E.Trips
  12. 开课吧9.9学python课_python 自动化运维 零基础入门 课程
  13. Java绿盾解密- Ldterm(绿盾加密文件解密)
  14. 有关初始位置检测,死区补偿,弱磁,MTPA,Foc保护措施
  15. vue组件库(Element UI)
  16. 《人类染色体与染色体病》学习笔记
  17. python 了解量化交易
  18. PG14新特性--恢复和VACUUM的加速
  19. FastAPI简单示例
  20. 什么是POSIX标准

热门文章

  1. vue项目中更新element-ui版本
  2. Android开发笔记(一百二十六)自定义音乐播放器
  3. java字符串元素置于最前_java_java编程常用技术(推荐),一:将String字符串放在最前面 - phpStudy...
  4. 如何在IEDA中连github
  5. 关于SQLServer2005的学习笔记——生日问题
  6. Python内置容器(2)——字典,迭代器,列表解析
  7. [linux]查看文件编码和编码转换
  8. saltstack event 实践
  9. 指针使用前应先初始化
  10. [译] Facebook杯2013年编程挑战赛——预选赛题目及答案