hdu 4418 Time travel

高斯消元 求期望

题意:数轴上有0~n-1 个点,你每次可能走k步,1<=k<=m ,概率为Pk。起点和终点和初始方向都输入。每次走到端点就转向。求到达终点走过路程的期望。

解法:为了方便处理转向,把n个点变成n=2*(n-2)个点。即0 1 2 3变成 0 1 2 3 2 1。确定好方向后,就可以直接列方程,设以pos为起点到达t经过的路程的期望为e[pos]。则有e[pos]=sigma(e[(pos+i)%k+i)*p[i] ,初始值显然为e[t]=e[(n-t)%n]=0。然后高斯消元解方程组即可,矩阵为n*(n+1)的矩阵。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#define eps 1e-8
#define INF 1e9
using namespace std;

double P[500] ;
int vis[500] ;
int n,m,y,x,d ,t ;
double a[500][500] ;
inline int sgn(double dd) {
    if (fabs(dd)<eps) return 0;
    return dd>0?1:-1;
}

bool bfs(int s)
{
    queue <int> que ;
    que.push(s) ;
    memset(vis, 0, sizeof vis);
    vis[s] = 1;
    while(!que.empty()){
        int d=que.front() ;
        que.pop() ;
        for(int i=1;i<=m;i++){
            if(sgn(P[i])){
                if(!vis[(d+i)%n]){
                    vis[(d+i)%n]=1;
                    que.push((d+i)%n) ;
                }

            }
        }
    }
    if(vis[y] || vis[(n-y)%n]) return 1;
    return 0;
}


int gauss(int N, int M) {
    int i, j, r, c, pvt;
    double maxp;
    for (r=0, c=0; r<N && c<M; ++r, ++c) {
        for (maxp=0, i=r; i < N; ++i)
            if (fabs(a[i][c])>fabs(maxp)) maxp = a[pvt=i][c];
        if (sgn(maxp)==0) {
            r--;
            continue;
        }
        if (pvt != r)
            for (j = r; j <= M; ++j) swap(a[r][j], a[pvt][j]);
        for (j = c+1; j <= M; ++j) {
            a[r][j] /= maxp;
            for (i = r+1; i < N; ++i)
                a[i][j] -= a[i][c]*a[r][j];
        }
    }
    for (i = r; i < N; ++i)
        if (sgn(a[i][M])) return -1;
    if (r < M) return M-r;
    for (i = M-1; i >= 0; --i)
        for (j = i+1; j < M; ++j)
            a[i][M] -= a[j][M]*a[i][j];
    return 0;
}
int main()
{

    scanf("%d",&t) ;
    while(t--){
        memset(vis, 0 , sizeof vis) ;
        scanf("%d%d%d%d%d",&n,&m,&y,&x,&d);
        for(int i=1;i<=m;i++){
            cin>>P[i] ;
            P[i]/=100;
        }
        n=(n-1) * 2;
        if(d>0) x=(n-x) % n;
        if(x==y){
            printf("0.00\n");
            continue ;
        }
        if(!bfs(x)){
            printf("Impossible !\n") ;
            continue ;
        }
        //ап╥╫Ёл
        memset(a,0,sizeof a);
        double sum=0.0 ;
        for(int i=1;i<=m ; i++){
            sum+=P[i]*i ;
        }
        for(int i=0;i<n;i++){
            a[i][i]=1;
            if(!vis[i]){
                a[i][n] = INF;
                continue ;
            }
            if(i==y || (n-y)%n == i){
                a[i][n]=0.0 ;
                continue ;
            }
            a[i][n]=sum;
            int pos= i;
            for(int j=1;j<=m;j++){

                pos=(pos+1)%n;
                a[i][pos]-=P[j];
            }
        }
        if(!gauss(n,n)){
            printf("%.2f\n",a[x][n]);
        }
        else printf("Impossible !\n");
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/Scale-the-heights/p/4703018.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值