ZOJ 3735 Josephina and RPG DP

题意:有M个人,我们任选3个人组成一个队伍,可以组成C(M,3)种队伍,给出这些队伍之间的胜率。现在,需要你战胜N个队伍。战胜该队伍,你可选择用战胜的队伍来替换你现有的队伍。现在要求战胜这N个队伍的最大概率。

思路:因为对于战胜的队伍,我们可以选择替换还是不替换,这就像01背包。因为N非常大,我们需要考虑O(N)的递推方程。

            如果我们从前向后递推,会存在一个后效性的问题,就是,当前的最优解可能不是全局的最优解。这就暗示了我们需要从后往前递推。

            如何从后向前递推呢?因为最后一个被战胜的队伍是确定的,那每个队战胜该队的概率就是确定的。而对于其他的队,我们有两种方式来战胜它,保持原来的队伍不变,用前一个队来替换自己的队伍来战胜它。而到底用哪一个就是取决与其中的最大值。

            因为有前后关系,我们要利用滚动数组。

代码如下:

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAX = 200;
const double EPS = 1e-6;

double r[MAX][MAX];
double ans[2][MAX];
int num[10010];
int M;
int N;

int dcmp(double x)
{
    if(fabs(x) < EPS)
        return 0;
    else if(x > 0) return 1;
    else return -1;
}

int main(void)
{
    while(scanf("%d",&M) != EOF){
        int n = M * (M-1)*(M-2) / 6;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                scanf("%lf",&r[i][j]);
        scanf("%d", &N);
        for(int i = 0; i < N; ++i)
            scanf("%d", &num[i]);
        int now = 0, pre = 1;
        for(int i = 0; i < n; ++i)
            ans[now][i] = r[i][num[N-1]];
        for(int i = N - 2; i >= 0; --i){
            swap(pre,now);
            for(int j = 0; j < n; ++j){
                double ret1 = ans[pre][j] * r[j][num[i]];
                double ret2 = ans[pre][num[i]] * r[j][num[i]];
                if(dcmp(ret1 - ret2) > 0)
                    ans[now][j] = ret1;
                else
                    ans[now][j] = ret2;
            }
        }
        double ret = 0;
        for(int i = 0; i < n; ++i)
            if(dcmp(ans[now][i] - ret) > 0)
                ret = ans[now][i];
        printf("%.6f\n",ret);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值