石头合并---动态规划详解

 

思想来源:
1 floyd
2 :隔板法
3 :动态规划

问题分析:
1 :只能是相邻两个石头才能合并
2 :操场是圆形的
3 :合并后的石头组成一个新的石堆
4 :要求求解最优的合并方式使得得分最大

  根据题意   什么才叫得分?

得分是合并的石头形成新的石堆的石头的数目,合并一个对应的得分就加上新合并的石堆石头的数目, 最后求解的分的总和

算法选择

蛮力法   时间复杂度大效率低下
贪心法   石头的堆数目相近的比较多时处理复杂   并且难以的到最优解
动态规划   下面将介绍

数据模拟

加入有石堆    石子   数目一次是
  1 2 3  则选择方式有
1): 1 ->2->3;  3+6 = 9
2)2->1->3  3+6 = 9
3)2->3->1 5+6 = 11
4)1->3->2 4+6 = 10
5)3->1->2  4+6 = 10
6)3->2->1 5+6 = 11
故最优解为 11


动态方程

约束条件   1=k<=j-1;
方程:
F(I,j) = max{f(I,k)+f(i+k,j-k)}+sum[i][j];

源码
#include <iostream> using namespace std; const int NUM = 100; int a[NUM]; int c[NUM][NUM]; int n; int value(int i,int j) { int t1 =0; int t2 = 0; for(int k = 0;k<j;k++) { t1+= a[(k+i-1)%n+1];//向后找j个值 t2+= a[(i-k+n-1)%n+1];//向前找j个值 } if(t1>t2) return t1; //返回两者中的较大的 else return t2; } int deal() { int i; int j; int k; int f[NUM][NUM]; //记录运行过程的数组 for(i = 1;i<=n;i++) f[i][0] = 0; //将走了0步的值设置为0 for(i = 1;i<=n;i++) for(j = 1;j<=n;j++) c[i][j]= value(i,j); //从i点出发找到j个数据的总和 int max = 0; //初始化max 为0 用于记录单次最大的值 (k) for(j= 2;j<=n;j++) //因为已初始化第一列所以仍然需要执行n-1次 for(i = 1;i<=n;i++) { max = 0;//每次进入的时候都初始化max = 0; for(k = 1;k<=j-1;k++) if(f[i][k]+ f[i+k][j-k]+c[i][j]>max) //取所有的分段情况与最大的进行比较 max = f[i][k]+ f[i+k][j-k]+c[i][j]; f[i][j] = max; //记录当前的i到j段中的最大值 } int ans = 0; //由于段长为n的才是我们要求解的解故最优解存在于段长为n的f[][]中   //返回最大值即可 for(i = 0;i<=n;i++) if(ans<f[i][n]) ans = f[i][n]; return ans; } int main() { cin>>n;//由用户确定输入的最大长度 int i = 0; int j = 0; for(i = 1;i<=n;i++) cin>>a[i]; //输入需要处理的数组 cout<<deal()<<endl; system("pause"); return 0; }  
 

 

你可能感兴趣的:(c,算法,System)