HDU4418:Time travel(高斯消元+期望)

传送门

题意

一个人在数轴上来回走,以pi的概率走i步i∈[1, m],给定n(数轴长度),m,e(终点),s(起点),d(方向),求从s走到e经过的点数期望

分析

设E[x]是人从x走到e经过点数的期望值,显然对于终点有:E[e] = 0
一般的:$$E[x] = \sum_i^m((E[x+i]+i) * p[i])$$
(走i步经过i个点,所以是E[x+i]+i)

建立模型:高斯消元每个变量都是一个互不相同的独立的状态,由于人站在一个点,还有一个状态是方向!例如人站在x点,有两种状态向前、向后,不能都当成一种状态建立方程,所以要把两个方向化为一个方向从而使状态不受方向的影响
实现:
n个点翻过去(除了头尾两个点~~~)变为2*(n-1)个点,例如:
\(6个点:012345 -> 0123454321\)
那么显然,从5开始向右走其实就是相当于往回走
然后方向就由两个状态转化成一个状态的,然后每个点就是只有一种状态了,对每个点建立方程高斯消元即可

bfs判断是否可以到达终点,顺便建立方程
参考KIDx的解题报告

trick

代码

#include<bits/stdc++.h>
using namespace std;  
#define M 205  
#define eps 1e-8  
int equ, var;  
double a[M][M], x[M];  
  
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 (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;  
}  
  
//has[x]表示人在x点时的变量号,因为我们只用可达状态建立方程,所以需要编号  
int has[M], vis[M], k, e, n, m;  
double p[M], sum;  
  
int bfs (int u)  
{  
    memset (has, -1, sizeof(has));  
    memset (a, 0, sizeof(a));           //忘记初始化WA勒,以后得注意  
    memset (vis, 0, sizeof(vis));  
    int v, i, flg = 0;  
    queue<int> q;  
    q.push (u);  
    k = 0;  
    has[u] = k++;  
    while (!q.empty ())  
    {  
        u = q.front ();  
        q.pop ();  
        if (vis[u]) continue;  
        vis[u] = 1;  
        if (u == e || u == n-e)     //终点有两个,你懂的~  
        {  
            a[has[u]][has[u]] = 1;  
            x[has[u]] = 0;  
            flg = 1;  
            continue;  
        }  
        //E[x] = sum ((E[x+i]+i) * p[i])  
        // ----> E[x] - sum(p[i]*E[x+i]) = sum(i*p[i])  
        a[has[u]][has[u]] = 1;  
        x[has[u]] = sum;  
        for (i = 1; i <= m; i++)  
        {  
            //非常重要!概率为0,该状态可能无法到达,如果还去访问并建立方程会导致无解  
            if (fabs (p[i]) < eps) continue;  
            v = (u + i) % n;  
            if (has[v] == -1) has[v] = k++;  
            a[has[u]][has[v]] -= p[i];  
            q.push (v);  
        }  
    }  
    return flg;  
}  
  
int main()  
{  
    int t, s, d, i;  
    scanf ("%d", &t);  
    while (t--)  
    {  
        scanf ("%d%d%d%d%d", &n, &m, &e, &s, &d);  
        n = 2*(n-1);  
        sum = 0;  
        for (i = 1; i <= m; i++)  
        {  
            scanf ("%lf", p+i);  
            p[i] = p[i] / 100;  
            sum += p[i] * i;  
        }  
        if (s == e)  
        {  
            puts ("0.00");  
            continue;  
        }  
        //一开始向左,起点要变  
        if (d > 0) s = (n - s) % n;  
        if (!bfs (s))  
        {  
            puts ("Impossible !");  
            continue;  
        }  
        equ = var = k;  
        Gauss ();  
        printf ("%.2f\n", x[has[s]]);  
    }  
    return 0;  
}  
posted @ 2017-04-19 12:57  遗风忘语  阅读(228)  评论(0编辑  收藏  举报