POJ 3756 Chess Game

Chess Game


高斯消元求期望

設dp[i]爲處在格子i走到格子N時的期望,很容易得出方程,但是存在後退操作,所以方程中會存在dp[j]其中j<i,不能直接遞推需要用高斯消元解方程組。可以先用DFS標記出能到達的點,然後按照這些能達到的點列出方程組,然後解方程即可。


/*
    author   : csuchenan
    prog     : POJ 3756
    algorithm: 高斯消元+期望
    csuchenan	3756	Accepted	252K	16MS	C++	3454B
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f
const int maxn = 100;
double martix[maxn+5][maxn+5];
double ans[maxn+5];
int fp[maxn+5], index[maxn];
bool reach[maxn+5];
int n;

int getNext(int v, int d){
    int p = v + d;
    if(p < 0 || p > n){
        p = n - (p%n + n)%n;
    }
    return p;
}

void dfs(int v){
    reach[v] = true;
    for(int i = 1; i <= 6; i ++){
        int p = getNext(v, i);
        if(fp[p]!= INF)
            p = getNext(p, fp[p]);
        if(!reach[p]){
            dfs(p);
        }
    }
}

void read(){
    int nf, tv, tu;
    memset(fp, 0x3f, sizeof(fp));
    scanf("%d", &n);
    scanf("%d", &nf);
    for(int i = 0; i < nf; i ++){
        scanf("%d%d", &tv, &tu);
        fp[tv] = tu;
    }
    scanf("%d", &nf);
    for(int i = 0; i < nf; i ++){
        scanf("%d%d", &tv, &tu);
        fp[tv] = -tu;
    }
    scanf("%d", &nf);
    for(int i = 0; i < nf; i ++){
        scanf("%d", &tv);
        fp[tv] = 0;
    }
}

void swap(double &x, double &y){
    double t = y;
    y = x;
    x = t;
}

double gauss(int x){
    int i, j, k, p;
    for(i = 0; i < x; i ++){
        p = i;
        for(j = i + 1 ; j < x ; j ++){
            if(fabs(martix[p][i]) < fabs(martix[j][i])){
                p = j;
            }
        }
        if(fabs(martix[p][i]) < eps){
            continue;
        }
        if(p != i){
            for(j = i; j <= x; j ++){
                swap(martix[p][j], martix[i][j]);
            }
        }
        for(j = i + 1; j < x; j ++){
            double r = martix[j][i]/martix[i][i];
            for(k = i; k <= x; k ++){
                martix[j][k] -= r * martix[i][k];
            }
        }
    }
    memset(ans, 0, sizeof(ans));
    for(i = x - 1; i >= 0; i --){
        double tmp = 0;
        for(j = x - 1; j > i; j --){
            tmp += martix[i][j] * ans[j];
        }
        ans[i] = (-martix[i][x] - tmp)/martix[i][i];
    }
    return ans[0];
}
void solve(){
    memset(reach, false, sizeof(reach));
    dfs(0);
    if(!reach[n]){
        printf("Impossible\n");
        return ;
    }
    int ls = 0;
    for(int i = 0; i < n; i ++){
        if(reach[i]){
            index[i] = ls ++;
        }
    }
    double one = 1.0/6.0;
    memset(martix, 0, sizeof(martix));
    for(int i = 0; i < n; i ++){
        if(!reach[i])
            continue;
        martix[index[i]][index[i]] = -1;
        for(int j = 1; j <= 6; j ++){
            int pn = getNext(i, j);
            int pfn = fp[pn];
            if(pfn != INF)
                pn = getNext(pn, fp[pn]);
            if(pn == n){
                martix[index[i]][ls] += one;
            }
            else if(pfn == 0){
                martix[index[i]][index[pn]] += one;
                martix[index[i]][ls] += one*2;
            }
            else{
                martix[index[i]][index[pn]] += one;
                martix[index[i]][ls] += one;
            }
        }
    }
    printf("%.2lf\n", gauss(ls));
}

int main(){
    read();
    solve();
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章