【codeforces24D】損壞的機器人
題目大意:有一只壞了的機器人站在一個n∗m的網格裏,初始位置在(x,y)。現在每個單位時間內它會隨機選左右下三個方向走,如果它隨機的方向會走出網格就不會往這個方向走。當然這個機器人也可能原地停留一個單位時間。求機器人走到第n行的期望時間。
只能說這題出得太吼辣~
我們用f[i][j]表示從(i,j)這個點走到第n行所需要的期望時間。那麽我們顯然得到:
f[i][1]=(f[i][1]+f[i][2]+f[i+1][1])/3+1;
f[i][j]=(f[i][j-1]+f[i][j]+f[i][j+1]+f[i+1][j])/4+1; j∈[2,m-1]
f[i][m]=(f[i][m]+f[i][m-1]+f[i+1][m])/3+1;
如果對上述的方程進行simple的高斯消元,很明顯是不行的.....
但還是要消一遍先~,得到:
f[i][1]=(3+f[i][2]+f[i+1][1])/2;
f[i][j]=(4+f[i][j+1]+f[i][j-1]+f[i+1][j])/3;
f[i][m]=(3+f[i][m-1]+f[i+1][m])/2;
不妨設f[i+1]是已知的,那麽,我們對該式子做一些細微調整。
以f[i][1]舉例 f[i][1] = (3+f[i][2]+f[i+1][1])/2 = (3+f[i+1][1])/3+1/2f[i][2]。
我們設(3+f[i+1][1])/3為A,1/2為B。
則f[i][2]= (4+f[i][3]+f[i][1]+f[i+1][j])/3 = (4+f[i][3]+A+B*f[i][2]+f[i+1][2])/3
化簡後得到 f[i][2]=(4+f[i][3]+A+f[i+1][2])/(3-B)。
與化簡f[1]的方式相同,將f[i][2]化為A+Bf[i+3],不難得到F[i][2]=(4+A+f[i+1][2])/(3-B) + 1/(3-B)*f[i][3],即A’=(4+A+C)/(3-B),B‘=1/(3-B)。 f[i][3...m-1]的推法與f[i][2]相同。(C為f[i+1][2])
下面考慮f[i][m],在此之前,我們已經求得f[i][m-1]=A+B*f[i][m]。 通過前面的推論我們得知:f[i][m]=(3+f[i][m-1]+f[i+1][m])/2,代入後得到f[i][m]=(3+A+B*f[i][m]+f[i+1][m])/2。
化簡後得到f[i][m]=(3+A+f[i+1][m])/(2-B)。f[i][m]的準確值終於被求出來了.....,由於先前的f[i][j]均推出了f[i][j]=A+B*f[i][j+1],所以該行的所有f值將全部求出。
這一過程重復n-x+1次即可。時間復雜度為O((n-x+1)*m)。
本題有個小坑:當m=1時,上文描述的轉移無效,此情況下轉移為f[i][1]=f[i+1][1]+2。(我就是忘記加這個特判所以沒有1A)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define M 1010 5 using namespace std; 6 double f[M][M]={0},a[M]={0},b[M]={0}; 7 8 int main(){ 9 int n,m,x,y; scanf("%d%d%d%d",&n,&m,&x,&y); 10 n=n-x+1; if(m==1) f[1][y]=(n-1)*2; 11 else 12 for(int i=n-1;i;i--){ 13 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 14 a[1]=(3+f[i+1][1])/2.; b[1]=1./2.; 15 for(int j=2;j<m;j++){ 16 double c=f[i+1][j]; 17 a[j]=(4.+a[j-1]+c)/(3-b[j-1]); 18 b[j]=1./(3-b[j-1]); 19 } 20 f[i][m]=(3.+a[m-1]+f[i+1][m])/(2.-b[m-1]); 21 for(int j=m-1;j;j--){ 22 f[i][j]=a[j]+b[j]*f[i][j+1]; 23 } 24 } 25 printf("%.10lf\n",f[1][y]); 26 }
【codeforces24D】損壞的機器人