HDU 4418 Time travel(高斯消元法求解概率DP)

Time travel

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 517    Accepted Submission(s): 80

Problem Description

Agent K is one of the greatest agents in a secret organization called Men in Black. Once he needs to finish a mission by traveling through time with the Time machine. The Time machine can take agent K to some point (0 to n-1) on the timeline and when he gets to the end of the time line he will come back (For example, there are 4 time points, agent K will go in this way 0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1, …). But when agent K gets into the Time machine he finds it has broken, which make the Time machine can’t stop (Damn it!). Fortunately, the time machine may get recovery and stop for a few minutes when agent K arrives at a time point, if the time point he just arrive is his destination, he’ll go and finish his mission, or the Time machine will break again. The Time machine has probability Pk% to recover after passing k time points and k can be no more than M. We guarantee the sum of Pk is 100 (Sum(Pk) (1 <= k <= M)==100). Now we know agent K will appear at the point X(D is the direction of the Time machine: 0 represents going from the start of the timeline to the end, on the contrary 1 represents going from the end. If x is the start or the end point of the time line D will be -1. Agent K want to know the expectation of the amount of the time point he need to pass before he arrive at the point Y to finish his mission.

If finishing his mission is impossible output “Impossible !” (no quotes )instead.  

 

Input There is an integer T (T <= 20) indicating the cases you have to solve. The first line of each test case are five integers N, M, Y, X .D (0< N,M <= 100, 0 <=X ,Y < 100 ). The following M non-negative integers represent Pk in percentile.  

 

Output For each possible scenario, output a floating number with 2 digits after decimal point

If finishing his mission is impossible output one line “Impossible !”

(no quotes )instead.  

 

Sample Input 2 4 2 0 1 0 50 50 4 1 0 2 1 100  

 

Sample Output 8.14 2.00  

 

Source
2012 ACM/ICPC Asia Regional Hangzhou Online  

 

Recommend liuyiding      
把N个点转成2*N-2个点。
然后就是高斯消元法求解概率DP了。

/*
HDU 4118
题目:给出一个数轴,有一个起点和一个终点,某个人可以
走1,2,3……m步,每一种情况有一个概率,初始有一个方向,
走到头则返回,问到达终点的期望步数为多少。

比较明显的高斯求期望问题
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<math.h>
using namespace std;

#define eps 1e-9
const int MAXN=220;
double a[MAXN][MAXN],x[MAXN];//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果
int equ,var;//方程数和未知数个数

int Gauss()
{
    int i,j,k,col,max_r;
    for(k=0,col=0;k<equ&&col<var;k++,col++)
    {
        max_r=k;
        for(i=k+1;i<equ;i++)
          if(fabs(a[i][col])>fabs(a[max_r][col]))
            max_r=i;
        if(fabs(a[max_r][col])<eps)return 0;
        if(k!=max_r)
        {
            for(j=col;j<var;j++)
              swap(a[k][j],a[max_r][j]);
            swap(x[k],x[max_r]);
        }
        x[k]/=a[k][col];
        for(j=col+1;j<var;j++)a[k][j]/=a[k][col];
        a[k][col]=1;
        for(i=0;i<equ;i++)
          if(i!=k)
          {
              x[i]-=x[k]*a[i][k];
              for(j=col+1;j<var;j++)a[i][j]-=a[k][j]*a[i][col];
              a[i][col]=0;
          }
    }
    return 1;
}

int num[MAXN];
double p[MAXN];
int cnt;
int n,N;//n=2*N-2
int M;
void bfs(int s)
{
    memset(num,-1,sizeof(num));
    queue<int>que;
    cnt=0;
    num[s]=cnt++;
    que.push(s);
    while(!que.empty())
    {
        int t=que.front();
        que.pop();
        for(int i=1;i<=M;i++)
        {
            if(fabs(p[i])<eps)continue;//这点很重要,这个想到不能达到的点
            int temp=(t+i)%n;
            if(num[temp]==-1)
            {
                num[temp]=cnt++;
                que.push(temp);
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int s,e;
    int D;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d",&N,&M,&e,&s,&D);
        for(int i=1;i<=M;i++){scanf("%lf",&p[i]);p[i]/=100;}

        if(e==s)//这个特判一定需要,否则可能N==1,会被0除,RE
        {
            printf("0.00\n");
            continue;
        }

        n=2*(N-1);
        if(D==1)s=n-s;
        bfs(s);
        if(num[e]==-1&&num[n-e]==-1)
        {
            printf("Impossible !\n");
            continue;
        }
        equ=var=cnt;
        memset(a,0,sizeof(a));
        memset(x,0,sizeof(x));
        for(int i=0;i<n;i++)
          if(num[i]!=-1)
          {
              if(i==e||i==n-e)
              {
                  a[num[i]][num[i]]=1;
                  x[num[i]]=0;
                  continue;
              }
              a[num[i]][num[i]]=1;
              for(int j=1;j<=M;j++)
              {
                  int t=(i+j)%n;
                  if(num[t]!=-1)
                  {
                      a[num[i]][num[t]]-=p[j];
                      x[num[i]]+=j*p[j];
                  }
              }
          }
        if(Gauss())printf("%.2lf\n",x[num[s]]);
        else printf("Impossible !\n");
    }
    return 0;
}

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/archive/2012/10/06/2713432.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞