HDU 4418 Time travel 期望dp+dfs+高斯消元

题目链接:

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

Time travel

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
#### 问题描述 > 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.

输入

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.

输出

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.

样例输入

2
4 2 0 1 0
50 50
4 1 0 2 1
100

样例输出

8.14
2.00

题意

一个人坐时光机,在时间轴上(0~n-1)来回运动,这个人向前运动k步的概率为p[k](k>=1&&k<=m),现在他要从X到Y,给你初始的X和初始运动方向,以及终点Y,问你他到终点时的期望步数。

题解

典型的dfs+高斯消元
首先我们可以把来回走拆成一条直线,如 0 1 2 可以拆成 0 1 2 1。这样就可以循环处理了。
然后dp[i]表示从i点到终点的期望步数,则有dp[i]=sigma(pro[x]*(dp[i+x]+x)),既sigma(pro[x]*dp[i+x])-dp[i]=-sigma(pro[x]*x)。列(n-1)*2个方程(只对那些起点可达的列方程),高斯求一下解就可以了。

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-9;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=233;

typedef double Matrix[maxn][maxn];

///n*(n+1)的增广矩阵
bool gauss_jordan(Matrix A,int n) {
    int i,j,k,r;
    for(i=0; i<n; i++) {
        r=i;
        for(j=i+1; j<n; j++) {
            if(fabs(A[j][i])>fabs(A[r][i])) r=j;
        }
        if(fabs(A[r][i])<eps) continue;
        if(r!=i) for(j=0; j<=n; j++) swap(A[r][j],A[i][j]);

        for(k=0; k<n; k++) if(k!=i) {
            for(j=n; j>=i; j--) A[k][j]-=A[k][i]/A[i][i]*A[i][j];
        }
    }

    ///矛盾式
    for(int i=n-1; i>=0&&fabs(A[i][i])<eps; i--) {
        if(fabs(A[i][n])>eps) return false;
    }
    return true;
}

Matrix A;

int n,m,Y,X,D;
int arr[maxn];
double pro[maxn];

int tot;
void get_arr(){
    tot=0;
    if(X==0){
        for(int i=0;i<n;i++) arr[tot++]=i;
        for(int i=n-2;i>0;i--) arr[tot++]=i;
    }else if(X==n-1){
        for(int i=n-1;i>=0;i--) arr[tot++]=i;
        for(int i=1;i<n-1;i++) arr[tot++]=i;
    }else if(D==0){
        for(int i=X;i<n;i++) arr[tot++]=i;
        for(int i=n-2;i>=0;i--) arr[tot++]=i;
        for(int i=1;i<X;i++) arr[tot++]=i;
    }else{
        for(int i=X;i>=0;i--) arr[tot++]=i;
        for(int i=1;i<n;i++) arr[tot++]=i;
        for(int i=n-2;i>X;i--) arr[tot++]=i;
    }
}

int vis[maxn];
bool flag=0;
void dfs(int u){
    vis[u]=1;
    if(arr[u]==Y) flag=true;
    for(int i=1;i<=m;i++){
        if(fabs(pro[i])<eps) continue;
        int des=(u+i)%tot;
        if(vis[des]) continue;
        dfs(des);
    }
}

void init(){
    clr(A,0);
    clr(vis,0);
}

int main() {
    int tc;
    scf("%d",&tc);
    while(tc--){
        scf("%d%d%d%d%d",&n,&m,&Y,&X,&D);
         for(int i=1;i<=m;i++){
            scf("%lf",&pro[i]); pro[i]/=100;
        }
        init();
        get_arr();

        flag=false;
        dfs(0);
        if(!flag){
            prf("Impossible !\n");
            continue;
        }

        for(int i=0;i<tot;i++){
            if(!vis[i]) continue;
            if(arr[i]==Y){
                A[i][i]=1.0;
                continue;
            }
            A[i][i]=-1.0,A[i][tot]=0;
            for(int j=1;j<=m;j++){
                int des=(i+j)%tot;
                A[i][des]+=pro[j];
                A[i][tot]-=pro[j]*j;
            }
        }

        bool su=gauss_jordan(A,tot);

        if(!su||fabs(A[0][0])<eps) prf("Impossible !\n");
        else prf("%.2lf\n",A[0][tot]/A[0][0]);
    }
    return 0;
}

//end-----------------------------------------------------------------------
posted @ 2016-10-18 14:06  fenicnn  阅读(144)  评论(0编辑  收藏  举报