1.描述:有一個由n個頂點構成的多邊形。每個頂點被賦予一個整數值,每條邊被賦予一個運算子“+”或“*”。所有邊依次用整數從1到n編號。
這裡寫圖片描述

遊戲第1步,將一條邊刪除。
隨後n-1步按以下方式操作:
(1)選擇一條邊E以及由E連線著的2個頂點V1和V2;
(2)用一個新的頂點取代邊E以及由E連線著的2個頂點V1和V2。將由頂點V1和V2的整數值通過邊E上的運算得到的結果賦予新頂點。
最後,所有邊都被刪除,遊戲結束。遊戲的得分就是所剩頂點上的整數值。

輸入:
輸入共兩行,第一行一個整數n表示頂點個數,第二行共2*n個數,分別為數字和字元。

例如:對於上圖中的問題,我們可以這樣按輸入樣例中的例子輸入,數學中的“+”號代表加法,小寫字母“x”代表乘法。

輸出:
一個整數,計算最高得分。

輸入樣例:
5
10 + -1 x -2 x 3 + -8 x

輸出樣例:
486

2.問題分析
解決該問題可用動態規劃中的最優子結構性質來解。
設所給的多邊形的頂點和邊的順時針序列為op[1],v[1],op[2],v[2],op[3],…,op[n],v[n] 其中,op[i]表示第i條邊所對應的運算子,v[i]表示第i個頂點上的數值,i=1~n。
在所給的多邊形中,從頂點i(1<=i<=n)開始,長度為j(鏈中有j個頂點)的順時針鏈p(i,j)可表示為v[i],op[i+1],…,v[i+j-1]。

設m1是對子鏈p[i][s]的任意一種合併方式得到的值,而a和b分別是在所有可能的合併中得到的最小值和最大值。m2是p[i+s][j-s]的任意一種合併方式得到的值,而c和d分別是在所有可能的合併中得到的最小值和最大值。依此定義有a≤m1≤b,c≤m2≤d
  (1)當op[i+s]=’+’時,顯然有a+c≤m≤b+d

  (2)當op[i+s]=’*’時,有min{ac,ad,bc,bd}≤m≤max{ac,ad,bc,bd}
  
換句話說,主鏈的最大值和最小值可由子鏈的最大值和最小值得到。例如,當m=ac時,最大主鏈由它的兩條最小主鏈組成;同理當m=bd時,最大主鏈由它的兩條最大子鏈組成。無論哪種情形發生,由主鏈的最優性均可推出子鏈的最優性。
綜上可知多邊形遊戲問題滿足最優子結構的性質。

3.遞迴求解

由前面的分析可知,為了求鏈合併的最大值,必須同時求子鏈合併的最大值和最小值。因此,在整個計算過程中,應同時計算最大值和最小值。

設m[i,j,0]是鏈p(i,j)合併的最小值,而m[i,j,1]是最大值。若最優合併在op[i+s]處將p(i,j)分為兩個長度小於j的子鏈p(i,i+s)和p(i+s,j-s),且從頂點i開始的長度小於j的子鏈的最大值和最小值均已經計算處。為了敘述方便,記

                     a=m[i,i+s,0]

                     b=m[i,i+s,1]

                     c=m[i+s,j-s,0]

                     d=m[i+s,j-s,1]

     (1)當op[i+s]='+'時,

                    m[i,j,0]=a+c

                   m[i,j,1]=b+d

     (2)當op[i+s]='*'是,

                    m[i,j,0]=min{ac,ad,bc,bd}

                    m[i,j,1]=max{ac,ad,bc,bd}

綜合(1)和(2),將p(i,j)在op[i+s]處斷開的最大值記為maxf(i,j,s),最小值記為minf(i,j,s),則

                                           a+c                               op[i+s]='+'

                    minf(i,j,s)={                                         

                                           min{ac,ad,bc,bd}           op[i+s]='*'

                                            b+d                                op[i+s]='+'     

                   maxf(i,j,s)={                                               

                                            max{ac,ad,bc,bd}          op[i+s]='*'

     由於多邊最優斷開位置s有1≤s≤j-1的j-1種情況,由此可知

                        m[i,j,0]=min{minf(i,j,s)}                  1≤i,j≤n  

                         m[i,j,1]=max{maxf(i,j,s)}                  1≤i,j≤n   

     初始邊界顯然為

                          m[i,j,0]=v[i]                  1≤i≤n

                           m[i,j,1]=v[i]                  1≤ i≤n

由於多邊形是封閉的,在上面的計算中,當i+s>n是,頂點i+s實際編號為(i+s)mod n。按上述遞推式計算出的m[i,n,1]即為首次刪去第i條邊後得到的最大得分。

4.演算法描述

基於以上討論可設計解多邊形遊戲問題的動態規劃演算法如下:

       void minMax(int i,int s,int j)
       {          int e[5];

       int a=m[i][s][0],

           b=m[i][s][1],

           r=(i+s-1)%n+1,//妙!

           c=m[r][j-s][0],

           d=m[r][j-s][1];

       if(op[r]=='t')

         {minf=a+c;

          maxf=b+d;

         }

       else

       {

           e[1]=a*c;

           e[2]=a*d;

           e[3]=b*c;

           e[4]=b*d;

           minf=e[1];

           maxf=e[1];

           for(int k=2;k<5 kh>

             {if(minf>e[k]) minf=e[k];

              if(maxf

             }

       }

}

int polyMax(){
for(int j=2;j<=n;j++)

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

    for(int s=1;s

      {minMax(i,s,j);

       m[i][j][0]=100000;

       m[i][j][1]=-100000;

       if(m[i][j][0]>minf) m[i][j][0]=minf;

       if(m[i][j][1]

      }

long int temp=m[1][n][1];

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

  if(temp

return temp;

}

【新方法】

本題在處理順時針迴圈時的下標時,有一個很妙的方法。即,

                        r=(i+s-1)%n+1

其實,本題從這樣編純屬巧合。

當i+s 並不需要減一的時候,用這種方法編就很方便。

如果用傳統的方法就是

            if(i==n)       r=n;

             else r=i%n

這樣,以來r=(i+s-1)%n+1就簡單了不少。

【參考程式】



#include

#include

long int minf,maxf,m[51][51][2];

char op[52];

int v[51],n;

void in()

{

     FILE *in=fopen("polygon2.in","r");

     fscanf(in,"%d",&n);

     fgetc(in);

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

       fscanf(in,"%c %d ",&op[i],&v[i]);

     fclose(in);

}    

void iniM()

{

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

       {m[i][1][0]=v[i];

        m[i][1][1]=v[i];

       }

}

void minMax(int i,int s,int j)

{

           int e[5];

           int a=m[i][s][0],

               b=m[i][s][1],

               r=(i+s-1)%n+1,//妙!

               c=m[r][j-s][0],

               d=m[r][j-s][1];

           if(op[r]=='t')

             {minf=a+c;

              maxf=b+d;

             }

           else

           {

               e[1]=a*c;

               e[2]=a*d;

               e[3]=b*c;

               e[4]=b*d;

               minf=e[1];

               maxf=e[1];

               for(int k=2;k<5 kh>

                 {if(minf>e[k]) minf=e[k];

                  if(maxf

                 }

           }

}                                     

int polyMax()

{

    for(int j=2;j<=n;j++)

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

        for(int s=1;s

          {minMax(i,s,j);

           m[i][j][0]=100000;

           m[i][j][1]=-100000;

           if(m[i][j][0]>minf) m[i][j][0]=minf;

           if(m[i][j][1]

          }

    long int temp=m[1][n][1];

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

      if(temp

    return temp;

}

int main()

{

    in();

    iniM();

    long int max=polyMax();

    printf("%ld\n",max);

    system("pause");

    return 0;

}  
.