这题的状态是循环依赖的有环。。
之前一道概率DP,类似有环。。但是它是可以消掉的
比如dp[i]=0.3*dp[i+1]+0.2*dp[i+2]+0.5*dp[i];
完全可以变成,0.5*dp[i]=0.3*dp[i+1]+0.2*dp[i+2]
然后把系数除过去就好了,
然而这个题是,dp[i]=0.5*dp[i+1]+0.5*dp[i-1]+1;
这个+1是什么意思呢,dp[i]->要到i+1,i-1任意两个状态之一,一定要付出1步的代价!
想一想背包问题。。类似的,
然后你会发现dp[i]还没递归完。。dp[i-1]和dp[i+1]又跑回来找它了。。。这不可能DP得出来
所以这个题正确的消环方法是,高斯消元
高斯消元我还不太会写。。待我学习一波回来写一写!
(学了高斯消元回来补辣!
我博客里的模板正常用是会TLE的!
需要剪枝!
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cmath> 5 #include <cstring> 6 using namespace std; 7 const double EPS=1e-8; 8 int n,p;double A[1005][1005]; 9 double x[1005]; 10 int Gauss(){ 11 for(int i=0;i<n;++i){ 12 int pivot=i; 13 for(int j=i+1;j<n;++j)if(abs(A[j][i]>abs(A[pivot][i]))) pivot=j; 14 if(pivot!=i) for(int k=0;k<n;++k) swap(A[i][k],A[pivot][k]); 15 if(abs(A[i][i])<EPS) return 0; 16 for(int j=i+1;j<=n;++j) A[i][j]/=A[i][i]; 17 for(int j=i+1;j<n;++j) 18 if(j!=i) { 19 if(abs(A[j][i])<EPS) continue; 20 for(int k=i+1;k<=n;++k) A[j][k]-=A[j][i]*A[i][k]; 21 } 22 } 23 for(int i=0;i<n;++i) x[i]=A[i][n]; double ans; 24 for(int i=n-1;i>=0;--i){ 25 ans=x[i]; 26 for(int j=i+1;j<n;++j) ans-=A[i][j]*x[j];x[i]=ans; 27 } 28 return 1; 29 } 30 int main(){ 31 int T;scanf("%d",&T); 32 while(T--){ 33 scanf("%d%d",&n,&p); 34 //构造系数矩阵 35 memset(A,0,sizeof(A)); 36 for(int i=0;i<n;++i){ 37 if(i==p) { 38 A[i][i]=1;A[i][n]=0; 39 continue; 40 } 41 A[i][i]=1;A[i][(i-1+n)%n]=-0.5; 42 A[i][(i+1)%n]=-0.5;A[i][n]=1; 43 } 44 Gauss(); 45 printf("%.4f ",x[0]); 46 } 47 return 0; 48 }
14行和19行是剪枝的地方,不减的话这题最高1000^3还是会T的