算法設計與分析——多邊形游戲(DP)


1、問題描述:   

      給定N個頂點的多邊形,每個頂點標有一個整數,每條邊上標有+(加)或是×(乘)號,並且N條邊按照順時針依次編號為1~N。下圖給出了一個N=4個頂點的多邊形。

     游戲規則 :(1) 首先,移走一條邊。

        (2) 然后進行下面的操作: 選中一條邊E,該邊有兩個相鄰的頂點,不妨稱為V1和V2。對V1和V2頂點所標的整數按照E上所標運算符號(+或是×)進行運算,得到一個整數;用該整數標注一個新頂點,該頂點代替V1和V2 。 持續進行此操作,直到最后沒有邊存在,即只剩下一個頂點。該頂點的整數稱為此次游戲的得分(Score)。

 

    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],如果這條鏈的最后一次合並運算在op[i+s]處發生(1<=s<=j-1),則可在op[i+s]處將鏈分割為兩個子鏈p(i,s)和p(i+s,j-s)。

      設m[i,j,0]是鏈p(i,j)合並的最小值,而m[i,j,1]是最大值。若最優合並在op[i+s]處將p(i,j)分為兩個長度小於j的子鏈的最大值和最小值均已計算出。即:

      a=m[i,s,0]  b=m[i,s,1]  c=m[i,s,0]  d=m[i,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}

     由於最優斷開位置s有1<=s<=j-1的j-1中情況。 初始邊界值為 m[i,1,0]=v[i]   1<=i<=n m[i,1,1]=v[i]   1<=i<=n

       因為多變形式封閉的,在上面的計算中,當i+s>n時,頂點i+s實際編號為(i+s)modn。按上述遞推式計算出的m[i,n,1]記為游戲首次刪除第i條邊后得到的最大得分。

代碼如下:

 

 1 //2015.5.2:——Anonymous
 2 #include<string.h>
 3 #include<stdio.h>
 4 int v[101];
 5 int n;
 6 char op[101];
 7 int minf,maxf;
 8 int m[101][101][2];
 9 void minMax(int i,int s,int j)
10 {
11     int e[5];
12     int a=m[i][s][0],
13         b=m[i][s][1],
14         r=(i+s-1)%n+1,
15         c=m[r][j-s][0],
16         d=m[r][j-s][1];
17     if(op[r]=='t')
18     {
19         minf=a+c;
20         maxf=b+d;
21     }
22     else
23     {
24         e[1]=a*c;
25         e[2]=a*d;
26         e[3]=b*c;
27         e[4]=b*d;
28         minf=e[1];
29         maxf=e[1];
30         for(int k=2; k<5; k++)
31         {
32             if(minf>e[k])
33                 minf=e[k];
34             if(maxf<e[k])
35                 maxf=e[k];
36         }
37     }
38 }
39 int main()
40 {
41     memset(m,0,sizeof(m));
42     scanf("%d",&n);
43     getchar();
44     for(int i=1; i<=n; i++)
45     {
46         scanf("%c",&op[i]);
47         scanf("%d",&v[i]);
48         m[i][1][0]=v[i];
49         m[i][1][1]=v[i];
50         getchar();
51     }
52     for(int j=2; j<=n; j++)//鏈的長度
53         for(int i=1; i<=n; i++)//刪掉第i條邊
54             for(int s=1; s<j; s++)//斷開的位置
55             {
56                 minMax(i,s,j);
57                 if(m[i][j][0]>minf)
58                     m[i][j][0]=minf;
59                 if(m[i][j][1]<maxf)
60                     m[i][j][1]=maxf;
61             }
62     int temp=m[1][n][1];
63     for(int i=2; i<=n; i++)
64     {
65         if(temp<m[i][n][1])
66             temp=m[i][n][1];
67     }
68     printf("%d\n",temp);
69     return 0;
70 }

 

測試數據:

 輸入:

4
t -7 t 4 x 2 x 5

輸出:

33

計算復雜性分析:

  與凸多邊形最有三角剖分問題類似,上述算法需要O(n3)計算時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM