您的位置:首页 > 其它

概率dp(求期望)+高斯消元 hdu-4418-Time travel

2013-08-29 10:58 471 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4418

题目大意:

有n个点标号为0~n-1,A从x点出发每次可以走1~m步,走k步的概率为pk, 如果到达了n-1点,则往回走即(n-1~0),求走到y时走的步数的概率。

解题思路:

概率dp+高斯消元。

因为0~n-1中的点都有方向,为了是方向统一,可以增加n-2个点,使统一向一个方向走0~n-1~0

n-1右边的点表示向左走,两种不同的状态。

dp[i]表示从i开始到达终点的步数期望 dp[i]=(dp[i+1]+1)*p1+(dp[i+2]+2)*p2+(dp[i+3]+3)*p3.......。

注意有些点不能到达,所以先BFS找能够到达的点,对于不能到达的点直接输出Impossible

然后构建2*n-2元方程求解就行了。注意有些步数不能走。

最好把能够有效的状态单独拿出来,直接重新构建方程。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);

#define Maxn 210
int gap[Maxn],cnt,nn;
int vis[Maxn],n,m,x,y,d;
double pp[Maxn];
double g[Maxn][Maxn],xx[Maxn];

void bfs()
{
   queue<int>myq;
   myq.push(x);
   vis[x]=true;
   while(!myq.empty())
   {

      int tmp=myq.front();
      myq.pop();
      if(tmp==y||tmp==nn-y) //到了终点后就不能再走了
         continue;
      for(int i=1;i<=cnt;i++)
      {
         int tt;
         tt=(tmp+gap[i])%nn; //统一转化成向一个方向走
         if(vis[tt])
            continue;
         vis[tt]=true;
         myq.push(tt);
      }
   }
}

void gg(int row,int col) //高斯消元 0~row 和0~col
{
   for(int i=0,j=0;i<row,j<col;i++,j++)
   {
      int t=i;
      for(int k=i+1;k<=row;k++)
         if(fabs(g[k][j])>fabs(g[t][j]))
            t=k;
      if(fabs(g[t][j])<eps)
         continue;
      if(t-i)
      {
         for(int k=i;k<=col;k++)
            swap(g[i][k],g[t][k]);
      }
      for(int q=i+1;q<=row;q++)
      {
         if(fabs(g[q][j])<eps) //该系数已经变成了0
            continue;
         double tmp=g[q][j]/g[i][j];
         g[q][j]=0.0;

         for(int k=j+1;k<=col;k++)
            g[q][k]-=tmp*g[i][k];
      }
   }
   for(int i=row;i>=0;i--)
   {
      if(fabs(g[i][i])<eps) //系数都为0了
         continue;
      xx[i]=g[i][col];
      for(int j=row;j>i;j--)
         xx[i]-=g[i][j]*xx[j];
      xx[i]/=g[i][i];
   }
}
int main()
{
   int t,a;

   scanf("%d",&t);
   while(t--)
   {
      scanf("%d%d%d%d%d",&n,&m,&y,&x,&d);
      cnt=0;
      double sum=0.0;
      for(int i=1;i<=m;i++)
      {
         scanf("%d",&a);
         if(a) //可走
         {
            gap[++cnt]=i; //能走的
            pp[cnt]=a*1.0/100.0;
            sum+=pp[cnt]*i;
         }
      }
      //cout<<sum<<endl;
      if(x==y) //起点和终点为同一点
      {
         printf("0.00\n");
         continue;
      }
      memset(vis,false,sizeof(vis));
      nn=2*n-2;
      if(d>0)
         x=nn-x; //两种不同的状态
      bfs();
      if(!vis[y]&&!vis[2*n-2-y]) //不能到达
      {
         printf("Impossible !\n");
         continue;
      }
      memset(g,0,sizeof(g));
      for(int i=0;i<nn;i++) //枚举开始的位置,注意一共有nn个未知数
      {
         if(!vis[i])
            continue;  //把不能到达的都清零,无效方程,没关系
         g[i][i]+=1.0; 
         if(i==y||i==nn-y)
            continue;
         for(int j=1;j<=cnt;j++) 
         {
           int tt=(i+gap[j])%nn;
           g[i][tt]-=pp[j];
         }
         g[i][nn]+=sum;
      }
      gg(nn-1,nn);
      printf("%0.2f\n",xx[x]);
   }
   return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: