codeforces24D. Broken robot

題面

題意

在n*m的棋盤中有一個機器人在(x,y),每個時刻它會等概率地從不動,向左走,向右走,向下走四種操作中選擇一種,但不能走出邊界,在邊界的機器人的選擇數量將變少,問機器人走到最後一行的期望步數是多少。

做法

如果直接進行dp會發現有後效性,因爲機器人可以向左也可以向右,但是在行與行之間的轉移是沒有後效性的,因此可以記dp值表示該點走到最後一行的期望步數,最後一行的dp值爲0,然後逐行向上轉移,但是因爲同一行的轉移是有後效性的,所以要用高斯消元來求解,這樣就可以得到一個時間複雜度爲O(nm3)O(n*m^3)的算法,但是太慢了。
我們可以觀察一下係數矩陣,發現它實際上只有從左上角到右下角一帶和最右邊的常數列是有數字的,且每行每列均至多隻有3個非零係數,因此進行一次高斯消元的時間複雜度並非O(m3)O(m^3),而是O(m)O(m)的,然後這題就可以做了。

代碼

#include<iostream>
#include<cstdio>
#include<cmath>
#define db double
#define eps 1e-8
#define N 1010
using namespace std;

int m,n,x,y;
db num[N][N],last[N];

void clear()
{
	int i,j;
	for(i=1;i<=n;i++)
	{
		num[i][n+1]=0;
		for(j=i-1;j<=i+1;j++)
		{
			num[i][j]=0;
		}
	}
}

inline void xy()
{
	int i,j,k;
	db t;
	for(i=1;i<=n;i++)
	{
		for(j=i+1;j<=n;j++)
		{
			if(fabs(num[j][i])<eps) break;
			t=num[j][i]/num[i][i];
			for(k=i;k<=n;k++)
			{
				if(fabs(num[i][k])<eps) break;
				num[j][k]-=t*num[i][k];
			}
			num[j][n+1]-=t*num[i][n+1];
		}
	}
}

int main()
{
	int i,j,k,t;
	db tmp;
	cin>>m>>n>>x>>y;
	if(m==x)
	{
		puts("0.0000000000");
		return 0;
	}
	for(i=m-1;i>=x;i--)
	{
		clear();
		for(j=1;j<=n;j++)
		{
			t=4-(j==1)-(j==n);
			tmp=1/(db)t;
			if(j>1) num[j][j-1]=tmp;
			if(j<n) num[j][j+1]=tmp;
			num[j][j]=tmp-1;
			num[j][n+1]=tmp*last[j]+1;
		}
		xy();
		for(j=n;j>=1;j--)
		{
			tmp=num[j][n+1];
			for(k=j+1;k<=n;k++)
			{
				if(fabs(num[j][k])<eps) break;
				tmp+=num[j][k]*last[k];
			}
			last[j]=-tmp/num[j][j];
		}
	}
	printf("%.10f",last[y]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章