hdu4870(高斯消元解概率DP)

这题真的是太为难我了,在接触这题之前,没学过概率dp,没学过高斯消元,为了这道题目,我特地去看了那两个算法,然后才回过来做这题

题意:有两个账号,没次去分数低的去参加比赛,赢的概率是P,赢了之后加1(这里以50为一个单位),输的概率是(1-P),输了之后减2

思路:设 x , y 是当前两个分数,那么状态转移为f ( x , y )  = 1 + p( x1 , y1 ) + (1 - p)(x2 , y2),经分析得有210个状态,分别为f(0, 0......19)、f(1, 1......19)......、f(19,19)

然后设用未知数x,x1,x2........x210代替它们,得到210个未知数,然后利用状态转移构造210个方程,最后用guass消元解就可以了

为什么用guass消元解,而不用递推解?因为状态转移方程有后效行,用递推解可以, 但是很难推

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>

#define N 300
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
double p;
double A[N][N];
int c[30][30];
int tot = 0;

void init() {
        memset(c, -1 ,sizeof(c));//??? 为什么一定要初始化为-1
        for (int i = 0; i < 20; ++i) {
                for (int j = 0; j <= i; ++j) {
                        c[i][j] = tot++;
                }
        }
        //printf("len = %d\n", len);

}
void get_A()//求系数矩阵A
{
    memset(A,0,sizeof(A));
    int i,j;
    int u,v;
    for(i = 0; i <= 19; i++)
    {
        for(j = 0; j < i; j++)
        {
            u = c[i][j];
            A[u][tot] = 1;
            A[u][u] = 1;
            v = c[i][max(0,j-2)];
            A[u][v] -= (1.0-p);
            v = c[i][j+1];
            A[u][v] -= p;
        }
        u = c[i][i];
        A[u][tot] = 1;
        A[u][u] = 1;
        v = c[i][max(0,j-2)];
        A[u][v] -= 1-p;
        v = c[i+1][i];
        A[u][v] -= p;
    }
}
void gauss_elimination(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(r != i)
            for(j = 0; j <= n; j++)
                swap(A[r][j],A[i][j]);
        for(j = n; j >= i; j--)
            for(k = i+1; k < n; k++)
                A[k][j] -= A[k][i]/A[i][i]*A[i][j];
    }
    for(i = n-1; i >= 0; i--)
    {
        for(j = i+1; j < n; j++)
            A[i][n] -= A[j][n]*A[i][j];
        A[i][n] /= A[i][i];
    }
}
int main()
{
    ios::sync_with_stdio(false);
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
    init();
    while(cin>>p)
    {
        get_A();
        gauss_elimination(210);
        printf("%.6lf\n",A[0][210]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值