HDU 2262 Where is the canteen 期望dp+高斯消元 Where is the canteen

题目链接:

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

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)
#### 问题描述 > After a long drastic struggle with himself, LL decide to go for some snack at last. But when steping out of the dormitory, he found a serious problem : he can't remember where is the canteen... Even worse is the campus is very dark at night. So, each time he move, he check front, back, left and right to see which of those four adjacent squares are free, and randomly walk to one of the free squares until landing on a canteen. #### 输入 > Each case begin with two integers n and m ( n<=15,m<=15 ), which indicate the size of the campus. Then n line follow, each contain m characters to describe the map. There are 4 different type of area in the map: > > '@' is the start location. There is exactly one in each case. > '#' is an impassible square. > '$' is a canteen. There may be more than one in the campus. > '.' is a free square. #### 输出 > Output the expected number of moves required to reach a canteen, which accurate to 6 fractional digits. If it is impossible , output -1. ####样例输入 > 1 2 > @$ > 2 2 > @. > .$ > 1 3 > @#$

样例输出

1.000000
4.000000
-1

题意

给你校园地图:n*m的网格,现在有个人从宿舍出来,要去食堂,由于天太黑,他看不见路,所以他会随机走到相邻的可以到达的点(也就是不是边界和墙,走过的点也还有可能走),问他到达食堂的期望步数。

题解

dp[i][j]表示在i,j点到达食堂需要的期望步数。
根据全期望公式易得:dp[i*m+j]=(ne1+ne2+...+nek)/k+1
明显有环,不能直接递推。数据很小,我们处理下式子:ne1+ne2+...+nek-k*dp[i*m+j]=-k。然后直接上高斯消元。

代码

#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;

char mat[22][22];
int n,m;
bool vis[22][22];

const int dx[]= {-1,1,0,0};
const int dy[]= {0,0,-1,1};

///求起点所在的联通块,其他不连通的地区不要啦进来算
bool flag;
void dfs(int x,int y) {
    vis[x][y]=1;
    if(mat[x][y]=='$') flag=true;
    for(int i=0; i<4; i++) {
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(nx<0||nx>=n||ny<0||ny>=m) continue;
        if(vis[nx][ny]) continue;
        if(mat[nx][ny]=='#') continue;
        dfs(nx,ny);
    }
}

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

int main() {
    while(scf("%d%d",&n,&m)==2) {
        init();
        for(int i=0; i<n; i++) scf("%s",mat[i]);
        int xs,ys;
        rep(i,0,n) rep(j,0,m) if(mat[i][j]=='@') {
            xs=i,ys=j;
            break;
        }
        flag=false;
        dfs(xs,ys);

        ///根本到不了任何食堂
        if(!flag){
            puts("-1");
            continue;
        }

        ///构造方程组
        int nn=n*m;
        rep(i,0,n) rep(j,0,m) {
            if(!vis[i][j]) continue;
            if(mat[i][j]=='$') {
                A[i*m+j][i*m+j]=1.0;
            } else {
                int k=0,ix=i*m+j;
                for(int ii=0; ii<4; ii++) {
                    int nx=i+dx[ii];
                    int ny=j+dy[ii];
                    if(nx<0||nx>=n||ny<0||ny>=m) continue;
                    if(!vis[nx][ny]) continue;
                    k++;
                    int iy=nx*m+ny;
                    A[ix][iy]=1.0;
                }
                A[ix][ix]=-1.0*k;
                A[ix][nn]=-1.0*k;
            }
        }

        bool su=gauss_jordan(A,nn);

        int p=xs*m+ys;
        if(!su||fabs(A[p][p])<eps) prf("-1
");
        else prf("%.6lf
",A[p][nn]/A[p][p]);
    }
    return 0;
}

//end-----------------------------------------------------------------------