動態規劃(DP)之多邊形遊戲問題

2022-01-14 21:09:39 字數 2990 閱讀 5989

問題描述:

多邊形遊戲是乙個單人玩的遊戲,開始時有乙個由n個頂點構成的多邊形。每個頂點被賦予乙個整數值,每條邊被賦予乙個運算子「+」或「*」。所有邊依次用整數從1到n編號。

遊戲第1步,將一條邊刪除。

隨後n-1步按以下方式操作:

(1)選擇一條邊e以及由e連線著的2個頂點v1和v2;

(2)用乙個新的頂點取代邊e以及由e連線著的2個頂點v1和v2。將由頂點v1和v2的整數值通過邊e上的運算得到的結果賦予新頂點。

最後,所有邊都被刪除,遊戲結束。遊戲的得分就是所剩頂點上的整數值。

問題:對於給定的多邊形,計算最高得分。

如下圖:

資料輸入:

第一行是乙個整數n

第二行按照

邊     頂點      邊     頂點     ….     邊     頂點

的順序以此存放了n個頂點和n條邊的標註資訊。

問題求解:

當把一條邊去除除后,再把它拉直,那麼這個問題就可以變成一條鏈。那麼就和以前寫的矩陣連乘有幾分的相似,其實我們最後要求的是這個鏈的表示式算式結果的最大值。於是我們就可以想到可以用陣列p[i][j]來表示從點i開始,鏈長為j的算術表示式的最大值,用v[i]儲存運算元,op[i]儲存操作符。如果這條鏈的最後一次合併運算在op[i+s]處發生(1≤s≤j-1),則可在op[i+s]處將鏈分割為2個子鏈p[i][s]和p[i+s][j-s]。似乎這樣再按照以前解決動態規劃題目時的思路,就可以解決問題了。   但是,我們再來考慮一下,由於有兩種運算子+和x,並且運算元可能存在負數,那麼我們也必須考慮兩個負數相乘的結果可能比兩個正數要打,所以我們同時還需要記錄每個鏈的最大和最小值,然後判斷,如果操作符為+的話,只需要兩個鏈的最大值相加即可,如果操作符是x的話,那麼必須把各種情況考慮進來,然後再求出最大值。分析如下:

設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]='*'時,由於v[i]可取負整數,子鏈的最大值相乘未必能得到主鏈的最大值,但是注意到最大值一定在邊界點取到,有min≤m≤max

換句話說,主鏈的最大值和最小值可由子鏈的最大值和最小值得到。例如,當m=ac時,最大主鏈由它的兩條最小子鏈組成;同理當m=bd時,最大主鏈由它的兩條最大子鏈組成

解決該問題可用動態規劃中的最優子結構性質來解。

設所給的多邊形的頂點和邊的順時針序列為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,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 ; m[i,j,1]=max

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

由於最優斷開位置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條邊後得到的最大得分。

**實現:

#include#include

int v[101

];int

n;char op[101

];int

minf,maxf;

int m[101][101][2

];void minmax(int i,int s,int

j)

else

}}int

main()

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

鏈的長度

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

刪掉第i條邊

for(int s=1; s//

斷開的位置

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

];

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

printf(

"%d\n

",temp);

return0;

}

結果輸出:

(由程式輸出可見初始時刪除的邊為序號1)

動態規劃 多邊形遊戲

已知乙個n邊的多邊形,在n個頂點上都有乙個整數,在n條邊上都存在 或 號。遊戲開始時,撤掉一條邊。剩下的就會變成由n個頂點,n 1條邊所組成的鏈條。將其中兩個相鄰的頂點按之間的運算子進行運算,這兩個頂點和這條邊被替換為運算結果,鏈條被削減為n 1個頂點,n 2條邊。如此反覆直到最後只剩下乙個點。多邊...

動態規劃 多邊形遊戲

1 問題描述 給定n個頂點的多邊形,每個頂點標有乙個整數,每條邊上標有 加 或是 乘 號,並且n條邊按照順時針 依次編號為1 n。下圖給出了乙個n 4個頂點的多邊形。遊戲規則 1 首先,移走一條邊。2 然後進行下面的操作 選中一條邊e,該邊有兩個相鄰的頂點,不妨稱為v1和v2。對v1和v2頂點所標的...

多邊形遊戲(區間動態規劃)

就是乙個區間動態規劃,為了處理環狀結構,乙個好的想法是把整個頂點和邊的序列在後面再複製一遍。可以比較簡化 實現的複雜度。include using namespace std const int maxn 105 struct calseq bool operator const calseq l ...