POJ 3744 Scout YYF I (矩阵优化,分段计算的概率DP)

参考:

http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710586.html

此题是一个用矩阵优化的求概率的题目。
主要思想是分段,根据转移方程用矩阵求解。
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-9;
const int MAXN=110;

struct Matrix{
    double mat[MAXN][MAXN];
    int n;
    Matrix () {}
    Matrix (int x, double v = 0)
    {
        n = x;
        REP(i, x) REP(j, x)
            mat[i][j] = i == j ? v : 0;
    }
    Matrix operator * (const Matrix &b) const
    {
        Matrix ret = Matrix(n);
        REP(i, n) REP(j, n) REP(r, n)
        {
            ret.mat[i][j] = (ret.mat[i][j] + mat[i][r] * b.mat[r][j]);
        }
        return ret;
    }
} ;

Matrix pow_M(Matrix a, int n)
{
    Matrix ret = Matrix(a.n, 1);
    Matrix temp = a;
    while (n)
    {
        if (n & 1) ret = ret * temp;
        temp = temp * temp;
        n >>= 1;
    }
    return ret;
}

int n;
double p;
int a[12];

void solve()
{
    Matrix e = Matrix(2);
    e.mat[0][0] = p;
    e.mat[0][1] = 1 - p;
    e.mat[1][0] = 1.0;
    e.mat[1][1] = 0.0;

    Matrix x = Matrix(2);
    x.mat[1][0] = 1.0;

    FED(i, n - 2, 0)
    {
        int d = a[i + 1] - a[i] - 1;
        Matrix y = pow_M(e, d);
        x = y * x;
        x.mat[1][0] = x.mat[0][0];
        x.mat[0][0] = 0;
    }
    int d = a[0] - 1;
    Matrix y = pow_M(e, d);
    x = y * x;
    printf("%.7lf\n", x.mat[0][0]);
}

//void solve()
//{
//
//    Matrix e = Matrix(2);
//    e.mat[0][0] = p;
//    e.mat[0][1] = 1 - p;
//    e.mat[1][0] = 1.0;
//    e.mat[1][1] = 0.0;
//    Matrix tmp;
//    tmp = pow_M(e, a[0] - 1);
//    double ans = 1.0;
//    ans *= (1 - tmp.mat[0][0]);
//    for (int i = 1; i < n; i++)
//    {
//        tmp = pow_M(e, a[i] - a[i - 1] - 1);
//        ans *= (1 - tmp.mat[0][0]);
//    }
//    printf("%.7lf\n", ans);
//}
int main ()
{
    while (~scanf("%d %lf", &n, &p))
    {
        REP(i, n) RI(a[i]);
        int fla = 0;
        REP(i, n)
        if (a[i] == 1)
        {
            printf("0.0000000\n");
            fla = 1;
            break;
        }
        if (fla) continue;
        sort(a, a + n);
        solve();
    }
    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值