湖南省第六屆大學生計算機程式設計競賽I
阿新 • • 發佈:2019-02-11
I - 射擊遊戲
A和B在玩一個射擊遊戲,戰場由若干單位正方形積木組成。積木佔據了連續的若干列,且圖形周長等於它最小包圍矩形的周長。下圖(a)是一個合法的戰場,但(b)和(c)都不是:(b)中有空列;(c)的圖形周長為14,而最小包圍矩形(用虛線畫出)的周長為12。受重力影響,每個積木的正下方要麼是地面,要麼是另一個積木。為了讓戰場看上去錯落有致、玩著更刺激,它不能恰好是一個矩形(即:不能每列積木都一樣高)。
遊戲規則如下:
1、 A和B輪流射擊,A先射擊。
2、 每次射擊時,首先選擇一行(該行必須至少有一個積木),以及“左”和“右”中的一個方向,然後往這個方向開火。子彈的威力為1~3的均勻隨機整數(即:威力為1、2、3的概率各為1/3),表示子彈能打掉的積木個數,被打掉的積木將直接從戰場中消失。如果該行的積木個數小於威力值,則子彈將在打掉該行所有積木後消失。例如,若選擇往右射擊從下往上數第3行,且威力為2,且這一行一共有4個積木,則最左邊的兩個積木將被打掉。注意:這兩個積木可以不連續。
3、 每次射擊完成後,懸空的積木垂直往下落。所有積木不再下落後,下一位選手才能開始射擊。
4、 誰打掉了最後一個積木,誰就獲勝。
假定開局是,根據規則1,A先開火。射擊後,B可能面臨的後續局面中的其中三個如下表:
行編號(從下往上數) |
子彈前進方向 |
威力(隨機值) |
剛射擊後 |
積木穩定後 |
2 |
從右往左 |
1 |
(同左圖) |
|
1 |
從右往左 |
2 |
||
1 |
從左往右 |
3 |
假定A和B都足夠聰明,採取讓自己獲勝概率儘量高的策略,你的任務是計算出A獲勝的概率。
Input輸入檔案最多包含25組測試資料,每個資料僅包含兩行,第一行是整數n(1<=n<=6),即積木的列數。第二行包含n個正整數h1, h2,..., hn(1<=hi<=6),表示從左往右數第i列的高度。積木的排列方式保證符合題目描述(即:圖形周長等於它最小包圍矩形的周長,且各列的高度不全相同)。n=0表示輸入結束,你的程式不應當處理這一行。Output對於每組資料,輸出僅一行,即A獲勝的概率,四捨五入保留六位小數。Sample Input3
2 1 1
0Sample Output
0.555556Hint
無
程式碼:
#include<iostream> #include<cstdio> using namespace std; #define X(A,B) (A[B[0]][B[1]][B[2]][B[3]][B[4]][B[5]]) double cache[7][7][7][7][7][7];//概率 bool vis[7][7][7][7][7][7];//統計 double win(int h[6]) { if(X(vis,h)) return X(cache,h); X(vis,h)=true; X(cache,h)=0.0; int mx=0; for(int i=0;i<6;i++) mx=max(mx,h[i]);//mx為最高列 int i=0,hh[6]; for(int j=0;j<mx;j++) { for(int d=0;d<2;d++) { i=5*d; double loss=0; for(int p=1;p<=3;p++) { for(int k=0;k<6;k++) hh[k]=h[k]; int pp=p; int k=i; while(pp) { if(k<0||k>5) break; if(hh[k]>j) hh[k]--,pp--; k+=1-2*d; } loss+=win(hh); } loss=(1-loss/3.0); if(loss>X(cache,h)) X(cache,h)=loss; } } return X(cache,h); } int main() { int n; while(scanf("%d",&n)==1&&n) { int h[6]={0}; for(int i=0;i<n;i++) scanf("%d",&h[i]); printf("%.6lf\n",win(h)); } return 0; }