博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

能量项链

Posted on 2010-10-20 11:20  桃子在路上  阅读(319)  评论(0编辑  收藏  举报

【能量项链】
    在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(Mars单位),新产生的珠子的头标记为m,尾标记为n。
    需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。
    例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:
(4⊕1)=10*2*3=60。
 这一串项链可以得到最优值的一个聚合顺序所释放的总能量为
((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。
【输入文件】
    输入文件energy.in的第一行是一个正整数N(4≤N≤100),表示项链上珠子的个数。第二行是N个用空格隔开的正整数,所有的数均不超过1000。第i个数为第i颗珠子的头标记(1≤i≤N),当i<N时,第i颗珠子的尾标记应该等于第i+1颗珠子的头标记。第N颗珠子的尾标记应该等于第1颗珠子的头标记。
    至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。
【输出文件】
输出文件energy.out只有一行,是一个正整数E(E≤2.1*109),为一个最优聚合顺序所释放的总能量。
【输入样例】
4
2 3 5 10
【输出样例】
710

【参考答案】

var
 n:integer;
 a:array[1..100] of longint;
 s:array[1..100,1..100] of longint;
 i,j,k,temp,max,min,t1,t2:longint;
begin
  assign(input,'energy.in');
  reset(input);
  assign(output,'energy.out');
  rewrite(output);
  readln(n);
  for i:=1 to n do
    read(a[i]);
  close(input);
  fillchar(s,sizeof(s),0);
  for j:=2 to n do
    for i:=1 to n do
      for k:=1 to j-1 do
        begin
          if i+k>n then t1:=i+k-n else t1:=i+k;   {前一颗珠子的尾标记}
          if i+j>n then t2:=i+j-n else t2:=i+j;   {后一颗珠子的尾标记}
          max:=s[i,k]+s[t1,j-k]+a[i]*a[t1]*a[t2];
          if s[i,j]<max then s[i,j]:=max;
        end;
  max:=0;
  for i:=1 to n do
    if max<s[i,j] then max:=s[i,j];
  write(max);
  close(output);
end.

 

【网上解题思路】
    简单的说:给你一项链,项链上有n颗珠子。相邻的两颗珠子可以合并(两个合并成一个)。合并的同时会放出一定的能量。不同的珠子的合并所释放的能量是不同的。问:按照怎样的次序合并才能使释放的能量最多?
  我们用top表示第i颗珠子的头标记,用wei表示第i颗珠子的尾标记,合并两颗相邻珠子所释放的能量是:
  Q=top*wei*wei[i+1]或top*top[i+1]*wei[i+1]; (一个样的)
  合并不一定按顺序的,本题所提供的样例也是导致出错的一大原因。
  n个珠子进行一次合并的后,就归结到了n-1个珠子的合并的问题。所以我们想到了动态规划。
  既然是dp题目,必然要满足dp的两大条件:、
  1.最优子结构性质;
  设Q[i,j]表示第i颗珠子到第j颗珠子合并所产生的能量。显然Q[1,n]表示的是合并产生的总的能量。给定一种标号方法,maxQ[1,n]就是所要求的。设最后一次合并在k处进行,则有Q[1,n]=Q[1,k]+Q[k+1,n]+top[1]*wei[k]*wei[n]。要Q[1,n]最大,必然要Q[1,k],Q[k+1,n]最大。
  证明:假设Q[1,k]不是最大,则必然存在一Q'[1,k]>Q[1,k]。
       那么就有Q'[1,n]=Q'[1,k]+Q[k+1,n]+top[1]*wei[k]*wei[n]>Q[1,k]。这与Q[1,n]的最优性矛盾。
  最优子结构性质得证。
   2.无后效性;
   无后效性是显然的,进行某次合并,合并前与合并后状态是相对独立,不相关联,互不影响的。
  
  算法已经定了下来了,关键是怎么实现了。
  项链是一个环,而我们处理是对一个串进行的。所以我们要把项链从某处割断展开,不同处的割断对应着不同的展开方法,也就是对应着不同的标号方法。产生的maxQ[1,n]也就不同的。所以我们要对这些maxQ[1,n]进行打擂,取其最大的一个,即为解了。
  dp的转移方程是:
   Best=maxQ[1,n] 1<=i<=n (i表示从第i颗珠子处展开,顺次标号);
   Q[i,j]=max{Q[i,k]+Q[k+1,j]+top*wei[k]*wei[j] 1<=i<=k<j<=n };
   其中Q[i,i]=0 1<=i<=n;
  dp的时间复杂度为O(n^3),n种的展开方法对应需要n次的dp,所以时间复杂度为O(n^4)。空间为O(n^2)。
  显然O(n^4)过这个题目是有点欠缺的,对的大的数据貌似很容易超时的。
  如果仔细想想,我们还是做了很不重复的工作的,不同的展开方式中必然存在着很多的大量的重复运算。于是还有很大的优化空间,既然展开做了很多的重复的工作,那么就合并起来吧。回到起点,开始的时候为什么我们要对项链做n次的展开呢,基于我们在运算的时候不能够实现第一颗珠子与第n颗珠子的相邻性。为了一次dp就实现所以的的珠子的相邻性,我们做如下处理:
    a[1],a[2],a[3]...a[n],a[1],a[2]...a[n-1] 
            (原来的)      (延伸的)

  也就是:
    a[1],a[2],a[3]...a[n],a[n+1],a[n+2]...a[m]   
  显然m=2n-1;
 我们对这一串珠子dp一次即可得解;dp方程为:
   Best=max{Q[i,i+n-1] 1<=i<=n}
    Q[i,j]=max{Q[i,k]+Q[k+1,j]+top*wei[k]*wei[j] 1<=i<=k<j<=min(i+n-1,m)}
  其中Q[i,i]=0 1<=i<=m;
  显然时间复杂度为O(n^3),空间为O(n^2)。min(i+n-1,m)已经对dp进行了优化。