您的位置:首页 > 其它

noip2006提高组之能量项链

2008-09-01 23:18 218 查看
点击下载noip2006提高组题目_代码_测试数据.rar

通过金矿模型介绍动态规划

/*

=========程序信息========

对应题目:noip2006提高组_能量项链

使用语言:c++

使用编译器:dev c++

使用算法:动态规划

算法运行时间:O(n^3)

作者:贵州大学05级 刘永辉

昵称:SDJL

编写时间:2008年9月

联系QQ:44561907

E-Mail:44561907@qq.com

获得更多文章请访问我的博客:www.cnblogs.com/sdjl

如果发现BUG或有写得不好的地方请发邮件告诉我:)

转载请保留此信息:)

=========题目解析========

此题的解析使用动态规划的9步思考方法,具体细节请参考《通过金矿模型介绍动态规划》一文

9步思考法步骤如下:

1、构造问题所对应的过程。

2、思考过程的最后一个步骤,看看有哪些选择情况。

3、找到最后一步的子问题,使得子问题符合“最优子结构”。

4、确保符合“子问题重叠”。

5、找到边界。

6、确保满足“子问题独立”。

7、考虑如何做备忘录。

8、分析所需时间是否满足要求。

9、写出转移方程式。

此题解析如下:

1、过程很明显,就是合并珠子的过程,从一串珠子共n颗开始,每次合并相邻的两颗为一颗,直到剩下一颗为止。

2、过程的最后一个步骤是把两颗珠子进行合并,这两颗珠子可以这样考虑,其中一颗是连续的r颗合并得到的,另一颗是其余的n-r颗连续的珠子合并得到的,那么选择

就是这个r颗连续的珠子如何选取,以顺时针选取考虑每颗珠子开头的情况,共有n种选择。

3、子问题是选择的这r颗连续的珠子最多能够得到多少能量,以及另外n-r颗连续的珠子最多能够得到多少能量,如果子问题能够得到最优的值,那么母问题在n种选择中

取出最大值则也必然最优,所以符合“最优子结构”。

4、母问题和子问题都是如何在一段珠子中选择一个左、右隔断点,使得最后在隔断点进行合并从而获得最多的能量,不同的是第一个问题需要考虑的是圆形项链,其它

问题需要的是考虑线形项链,因此我们可以把第一个问题选中r颗珠子后剩余的问题(线形的)和子问题(所有子问题都是线形的)看成是重叠的。

5、边界就是仅有一颗或两颗珠子的时候。

6、每一个问题的子问题有两个,都是考虑如何进行合并,因为子问题之间不会使用到同一颗珠子,所以满足独立。

7、用energy[i][j]记录从第i颗珠子到第j颗珠子组成的珠子片断能够得到的最大能量。

8、子问题数为O(n^2),每个问题有O(n)个选择,时间为O(n^3),满足n<=100。

9、参考程序代码。

*/

#include <cstdlib>

#include <iostream>

#include <fstream>

using namespace std;

const int maxCount = 100;//程序允许的最多珠子数

int n;//珠子数

int v[maxCount * 2];//v[i]表示第(i % n)颗珠子的能量,%表示求余

int energy[maxCount * 2][maxCount * 2];//energy[i][j]表示从第i颗珠子到第j颗珠子组成的珠子片断能够得到的最大能量

//初始化

void init()

{

ifstream inputFile("energy.in");

inputFile>>n;

for(int i=0; i<n ; i++)

{

inputFile>>v[i];

v[i + n] = v[i];//保存两便,便于后面的“剪断”操作

}

inputFile.close();

for(int i=0; i<maxCount; i++)

for(int j=0; j<maxCount; j++)

{

energy[i][j] = -1;//等于-1表示未知

}

}

//获得第i颗珠子到第j颗珠子组成的珠子片断能够得到的最大能量

int GetMaxEnergy(int startIndex, int endIndex)

{

//申明能够得到的最大能量

int retMaxEnergy;

//读备忘录

if(energy[startIndex][endIndex] != -1)

{

retMaxEnergy = energy[startIndex][endIndex];

}

//考虑边界只有一颗珠子时

else if(startIndex == endIndex)

{

retMaxEnergy =energy[startIndex][endIndex];

}

//考虑边界只有两颗珠子时

else if(startIndex + 1 == endIndex)

{

retMaxEnergy = v[startIndex] * v[endIndex] * v[endIndex + 1];

}

//考虑最优子结构

else

{

retMaxEnergy = 0;

//循环选取中断点,中断点在k和k+1之间

for(int k=startIndex ; k < endIndex; k++)

{

//获得左边能够得到的能量

int leftEnergy = GetMaxEnergy(startIndex,k);

//获得右边能够得到的能量

int rightEnergy = GetMaxEnergy(k+1,endIndex);

//获得总共能够得到的能量

int totalEnergy = leftEnergy + rightEnergy + (v[startIndex] * v[k+1] * v[endIndex+1]);

//保存最大值

retMaxEnergy = max(retMaxEnergy, totalEnergy);

}

}

//写备忘录

energy[startIndex][endIndex] = retMaxEnergy;

return retMaxEnergy;

}

void show()

{

//申明最优值best

int best = 0;

//最优值为所有k到k+n-1之间获得的能量的最大值,其中k为0到n-1,就好比把圆形项链一剪刀剪为线形的,而k就是剪断的位置

for(int k = 0; k<n; k++)

{

int getEnergy = GetMaxEnergy(k, k + n - 1);

best = max(best, getEnergy);

}

//输出最优值

cout<<best;

}

int main(int argc, char *argv[])

{

//初始化数据

init();

//显示结果

show();

system("PAUSE");

return EXIT_SUCCESS;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: