首先这题可以用期望DP来计算最后的期望值,由于这题每张卡片对应的概率是不相同的,所以不能像POJ-2096那样dp[i]表示拿到了i 张卡片来表示状态,而是要开一个 1<<N的状态来压缩状态表示拿到不用的卡片的期望值。对于给定的N,我们有dp[(1<<N)-1]=0,因为这已经是最后的状态了。
对于dp[i] 我们需要分析其能够到达的状态,如果 N=6, i 的二进制位为 011011,那么可能买零食不改变原来状态,也就是中了已经有了的卡片或者是没有中卡片,所以到达原来状态的概率是p[1]+p[2]+p[4]+p[5]+NONE,这一项是要移到待会儿方程的左边去解的,因为dp[i]还未知,不能够直接带入求解。那么 i 能够到达哪些状态呢?这里就是凡是为0的位都可以到达,前面写了个(1<<bit)^i 来判定是否为零错了,应该还是要 !((1<<bit) & i) 来判定靠谱...... 转移到下一个状态的概率就非常好算了,直接乘以该位对应的概率就可以了。
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> using namespace std; int N; double seq[25], dp[1100000], p[1100000]; void pre() { int LIM = 1 << N; for (int i = 0; i < LIM; ++i) { p[i] = 0; for (int j = 0; j < N; ++j) { if ((1 << j) & i) { // 低位对应编号小的概率 p[i] += seq[j+1]; } } } } int main() { int temp; double none, tot, myself; while (scanf("%d", &N) == 1) { dp[(1<<N)-1] = none = 0; for (int i = 1; i <= N; ++i) { scanf("%lf", &seq[i]); none += seq[i]; } none = 1 - none; pre(); for (int i = (1<<N)-2; i >= 0; --i) { tot = 0; myself = p[i] + none; for (int j = 0; j < N; ++j) { if (!((1 << j)&i)) { temp = i | (1 << j); tot += seq[j+1] * dp[temp]; } } dp[i] = (tot + 1) / (1 - myself); } printf("%.6lf\n", dp[0]); } return 0; }
这题真心不明白容斥定理是怎么来的。
代码如下:
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; int N; double seq[25]; int main() { int mask, odd; double sum, ret; while (scanf("%d", &N) == 1) { ret = 0; for (int i = 1; i <= N; ++i) { scanf("%lf", &seq[i]); } mask = 1<<N; for (int i = 1; i < mask; ++i) { odd = 0; sum =0; for (int j = 0; j < N; ++j) { if ((1 << j) & i) { ++odd; sum += seq[j+1]; } } if (odd & 1) { // 加奇减偶 ret += 1./sum; } else { ret -= 1./sum; } } printf("%.6lf\n", ret); } return 0; }