题意:有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;
}